1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32 
33 /* -- unixpw.c -- */
34 
35 #ifdef __linux__
36 /* some conflict with _XOPEN_SOURCE */
37 extern int grantpt(int);
38 extern int unlockpt(int);
39 extern char *ptsname(int);
40 #endif
41 
42 #ifndef DO_NOT_DECLARE_CRYPT
43 extern char *crypt(const char*, const char *);
44 #endif
45 
46 #include "x11vnc.h"
47 #include "scan.h"
48 #include "cleanup.h"
49 #include "xinerama.h"
50 #include "connections.h"
51 #include "user.h"
52 #include "connections.h"
53 #include "sslhelper.h"
54 #include "cursor.h"
55 #include "rates.h"
56 #include <rfb/default8x16.h>
57 
58 #if LIBVNCSERVER_HAVE_FORK
59 #if LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_WAITPID
60 #define UNIXPW_SU
61 #endif
62 #endif
63 
64 #ifdef IGNORE_GETSPNAM
65 #undef LIBVNCSERVER_HAVE_GETSPNAM
66 #define LIBVNCSERVER_HAVE_GETSPNAM 0
67 #endif
68 
69 #if LIBVNCSERVER_HAVE_PWD_H && LIBVNCSERVER_HAVE_GETPWNAM
70 #if LIBVNCSERVER_HAVE_CRYPT || LIBVNCSERVER_HAVE_LIBCRYPT
71 #define UNIXPW_CRYPT
72 #if LIBVNCSERVER_HAVE_GETSPNAM
73 #include <shadow.h>
74 #endif
75 #endif
76 #endif
77 
78 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H
79 #include <sys/ioctl.h>
80 #endif
81 #if LIBVNCSERVER_HAVE_TERMIOS_H
82 #include <termios.h>
83 #endif
84 #if LIBVNCSERVER_HAVE_SYS_STROPTS_H
85 #include <sys/stropts.h>
86 #endif
87 
88 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
89 #define IS_BSD
90 #endif
91 #if (defined(__MACH__) && defined(__APPLE__))
92 #define IS_BSD
93 #endif
94 
95 int white_pixel(void);
96 void unixpw_screen(int init);
97 void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
98 void unixpw_accept(char *user);
99 void unixpw_deny(void);
100 void unixpw_msg(char *msg, int delay);
101 int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp);
102 int unixpw_cmd_run(char *user, char *pass, char *cmd, char *line, int *n);
103 int crypt_verify(char *user, char *pass);
104 int cmd_verify(char *user, char *pass);
105 void unixpw_verify_screen(char *user, char *pass);
106 
107 static int text_x(void);
108 static int text_y(void);
109 static void set_db(void);
110 
111 int unixpw_in_progress = 0;
112 int unixpw_denied = 0;
113 int unixpw_in_rfbPE = 0;
114 int unixpw_login_viewonly = 0;
115 int unixpw_tightvnc_xfer_save = 0;
116 rfbBool unixpw_file_xfer_save = FALSE;
117 time_t unixpw_last_try_time = 0;
118 rfbClientPtr unixpw_client = NULL;
119 
120 int keep_unixpw = 0;
121 char *keep_unixpw_user = NULL;
122 char *keep_unixpw_pass = NULL;
123 char *keep_unixpw_opts = NULL;
124 
125 static unsigned char default6x13FontData[2899]={
126 0x00,0x00,0xA8,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0xA8,0x00,0x00, /* 0 */
127 0x00,0x00,0x00,0x00,0x20,0x70,0xF8,0x70,0x20,0x00,0x00,0x00,0x00, /* 1 */
128 0xA8,0x54,0xA8,0x54,0xA8,0x54,0xA8,0x54,0xA8,0x54,0xA8,0x54,0xA8, /* 2 */
129 0x00,0x00,0xA0,0xA0,0xE0,0xA0,0xA0,0x38,0x10,0x10,0x10,0x00,0x00, /* 3 */
130 0x00,0x00,0xE0,0x80,0xC0,0x80,0xB8,0x20,0x30,0x20,0x20,0x00,0x00, /* 4 */
131 0x00,0x00,0x60,0x80,0x80,0x60,0x30,0x28,0x30,0x28,0x28,0x00,0x00, /* 5 */
132 0x00,0x00,0x80,0x80,0x80,0xE0,0x38,0x20,0x30,0x20,0x20,0x00,0x00, /* 6 */
133 0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 7 */
134 0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0xF8,0x00,0x00,0x00, /* 8 */
135 0x00,0x00,0x90,0xD0,0xB0,0x90,0x20,0x20,0x20,0x20,0x38,0x00,0x00, /* 9 */
136 0x00,0x00,0xA0,0xA0,0xA0,0x40,0x40,0x38,0x10,0x10,0x10,0x00,0x00, /* 10 */
137 0x20,0x20,0x20,0x20,0x20,0x20,0xE0,0x00,0x00,0x00,0x00,0x00,0x00, /* 11 */
138 0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20, /* 12 */
139 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x20,0x20,0x20,0x20,0x20,0x20, /* 13 */
140 0x20,0x20,0x20,0x20,0x20,0x20,0x3C,0x00,0x00,0x00,0x00,0x00,0x00, /* 14 */
141 0x20,0x20,0x20,0x20,0x20,0x20,0xFC,0x20,0x20,0x20,0x20,0x20,0x20, /* 15 */
142 0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16 */
143 0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 17 */
144 0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00, /* 18 */
145 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x00,0x00, /* 19 */
146 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, /* 20 */
147 0x20,0x20,0x20,0x20,0x20,0x20,0x3C,0x20,0x20,0x20,0x20,0x20,0x20, /* 21 */
148 0x20,0x20,0x20,0x20,0x20,0x20,0xE0,0x20,0x20,0x20,0x20,0x20,0x20, /* 22 */
149 0x20,0x20,0x20,0x20,0x20,0x20,0xFC,0x00,0x00,0x00,0x00,0x00,0x00, /* 23 */
150 0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x20,0x20,0x20,0x20,0x20,0x20, /* 24 */
151 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /* 25 */
152 0x00,0x00,0x00,0x18,0x60,0x80,0x60,0x18,0x00,0xF8,0x00,0x00,0x00, /* 26 */
153 0x00,0x00,0x00,0xC0,0x30,0x08,0x30,0xC0,0x00,0xF8,0x00,0x00,0x00, /* 27 */
154 0x00,0x00,0x00,0x00,0x00,0xF8,0x50,0x50,0x50,0x50,0x50,0x00,0x00, /* 28 */
155 0x00,0x00,0x00,0x00,0x00,0x08,0xF8,0x20,0xF8,0x80,0x00,0x00,0x00, /* 29 */
156 0x00,0x00,0x30,0x48,0x40,0x40,0xE0,0x40,0x40,0x48,0xB0,0x00,0x00, /* 30 */
157 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00, /* 31 */
158 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 */
159 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, /* 33 */
160 0x00,0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 34 */
161 0x00,0x00,0x00,0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00,0x00,0x00, /* 35 */
162 0x00,0x00,0x20,0x78,0xA0,0xA0,0x70,0x28,0x28,0xF0,0x20,0x00,0x00, /* 36 */
163 0x00,0x00,0x48,0xA8,0x50,0x10,0x20,0x40,0x50,0xA8,0x90,0x00,0x00, /* 37 */
164 0x00,0x00,0x00,0x40,0xA0,0xA0,0x40,0xA0,0x98,0x90,0x68,0x00,0x00, /* 38 */
165 0x00,0x00,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 39 */
166 0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x00, /* 40 */
167 0x00,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x00, /* 41 */
168 0x00,0x00,0x00,0x20,0xA8,0xF8,0x70,0xF8,0xA8,0x20,0x00,0x00,0x00, /* 42 */
169 0x00,0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,0x00,0x00, /* 43 */
170 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x20,0x40,0x00, /* 44 */
171 0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, /* 45 */
172 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x70,0x20,0x00, /* 46 */
173 0x00,0x00,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0x80,0x00,0x00, /* 47 */
174 0x00,0x00,0x20,0x50,0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00,0x00, /* 48 */
175 0x00,0x00,0x20,0x60,0xA0,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, /* 49 */
176 0x00,0x00,0x70,0x88,0x88,0x08,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, /* 50 */
177 0x00,0x00,0xF8,0x08,0x10,0x20,0x70,0x08,0x08,0x88,0x70,0x00,0x00, /* 51 */
178 0x00,0x00,0x10,0x10,0x30,0x50,0x50,0x90,0xF8,0x10,0x10,0x00,0x00, /* 52 */
179 0x00,0x00,0xF8,0x80,0x80,0xB0,0xC8,0x08,0x08,0x88,0x70,0x00,0x00, /* 53 */
180 0x00,0x00,0x70,0x88,0x80,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00, /* 54 */
181 0x00,0x00,0xF8,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x00,0x00, /* 55 */
182 0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, /* 56 */
183 0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x08,0x88,0x70,0x00,0x00, /* 57 */
184 0x00,0x00,0x00,0x00,0x20,0x70,0x20,0x00,0x00,0x20,0x70,0x20,0x00, /* 58 */
185 0x00,0x00,0x00,0x00,0x20,0x70,0x20,0x00,0x00,0x30,0x20,0x40,0x00, /* 59 */
186 0x00,0x00,0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x08,0x00,0x00, /* 60 */
187 0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, /* 61 */
188 0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x80,0x00,0x00, /* 62 */
189 0x00,0x00,0x70,0x88,0x88,0x08,0x10,0x20,0x20,0x00,0x20,0x00,0x00, /* 63 */
190 0x00,0x00,0x70,0x88,0x88,0x98,0xA8,0xA8,0xB0,0x80,0x78,0x00,0x00, /* 64 */
191 0x00,0x00,0x20,0x50,0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00,0x00, /* 65 */
192 0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00, /* 66 */
193 0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00, /* 67 */
194 0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00, /* 68 */
195 0x00,0x00,0xF8,0x80,0x80,0x80,0xF0,0x80,0x80,0x80,0xF8,0x00,0x00, /* 69 */
196 0x00,0x00,0xF8,0x80,0x80,0x80,0xF0,0x80,0x80,0x80,0x80,0x00,0x00, /* 70 */
197 0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x98,0x88,0x88,0x70,0x00,0x00, /* 71 */
198 0x00,0x00,0x88,0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x88,0x00,0x00, /* 72 */
199 0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 73 */
200 0x00,0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00, /* 74 */
201 0x00,0x00,0x88,0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x88,0x00,0x00, /* 75 */
202 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00,0x00, /* 76 */
203 0x00,0x00,0x88,0x88,0xD8,0xA8,0xA8,0x88,0x88,0x88,0x88,0x00,0x00, /* 77 */
204 0x00,0x00,0x88,0xC8,0xC8,0xA8,0xA8,0x98,0x98,0x88,0x88,0x00,0x00, /* 78 */
205 0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 79 */
206 0x00,0x00,0xF0,0x88,0x88,0x88,0xF0,0x80,0x80,0x80,0x80,0x00,0x00, /* 80 */
207 0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0xA8,0x70,0x08,0x00, /* 81 */
208 0x00,0x00,0xF0,0x88,0x88,0x88,0xF0,0xA0,0x90,0x88,0x88,0x00,0x00, /* 82 */
209 0x00,0x00,0x70,0x88,0x80,0x80,0x70,0x08,0x08,0x88,0x70,0x00,0x00, /* 83 */
210 0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, /* 84 */
211 0x00,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 85 */
212 0x00,0x00,0x88,0x88,0x88,0x88,0x50,0x50,0x50,0x20,0x20,0x00,0x00, /* 86 */
213 0x00,0x00,0x88,0x88,0x88,0x88,0xA8,0xA8,0xA8,0xA8,0x50,0x00,0x00, /* 87 */
214 0x00,0x00,0x88,0x88,0x50,0x50,0x20,0x50,0x50,0x88,0x88,0x00,0x00, /* 88 */
215 0x00,0x00,0x88,0x88,0x50,0x50,0x20,0x20,0x20,0x20,0x20,0x00,0x00, /* 89 */
216 0x00,0x00,0xF8,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0xF8,0x00,0x00, /* 90 */
217 0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, /* 91 */
218 0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x10,0x10,0x08,0x08,0x00,0x00, /* 92 */
219 0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, /* 93 */
220 0x00,0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 94 */
221 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00, /* 95 */
222 0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 96 */
223 0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 97 */
224 0x00,0x00,0x80,0x80,0x80,0xF0,0x88,0x88,0x88,0x88,0xF0,0x00,0x00, /* 98 */
225 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x88,0x70,0x00,0x00, /* 99 */
226 0x00,0x00,0x08,0x08,0x08,0x78,0x88,0x88,0x88,0x88,0x78,0x00,0x00, /* 100 */
227 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0xF8,0x80,0x88,0x70,0x00,0x00, /* 101 */
228 0x00,0x00,0x30,0x48,0x40,0x40,0xF0,0x40,0x40,0x40,0x40,0x00,0x00, /* 102 */
229 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x88,0x70, /* 103 */
230 0x00,0x00,0x80,0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x88,0x00,0x00, /* 104 */
231 0x00,0x00,0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 105 */
232 0x00,0x00,0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x90,0x90,0x60, /* 106 */
233 0x00,0x00,0x80,0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00,0x00, /* 107 */
234 0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 108 */
235 0x00,0x00,0x00,0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x88,0x00,0x00, /* 109 */
236 0x00,0x00,0x00,0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x88,0x00,0x00, /* 110 */
237 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 111 */
238 0x00,0x00,0x00,0x00,0x00,0xF0,0x88,0x88,0x88,0xF0,0x80,0x80,0x80, /* 112 */
239 0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x78,0x08,0x08,0x08, /* 113 */
240 0x00,0x00,0x00,0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x80,0x00,0x00, /* 114 */
241 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x60,0x10,0x88,0x70,0x00,0x00, /* 115 */
242 0x00,0x00,0x00,0x40,0x40,0xF0,0x40,0x40,0x40,0x48,0x30,0x00,0x00, /* 116 */
243 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x98,0x68,0x00,0x00, /* 117 */
244 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x50,0x20,0x00,0x00, /* 118 */
245 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00,0x00, /* 119 */
246 0x00,0x00,0x00,0x00,0x00,0x88,0x50,0x20,0x20,0x50,0x88,0x00,0x00, /* 120 */
247 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x08,0x88,0x70, /* 121 */
248 0x00,0x00,0x00,0x00,0x00,0xF8,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, /* 122 */
249 0x00,0x18,0x20,0x20,0x20,0x20,0xC0,0x20,0x20,0x20,0x20,0x18,0x00, /* 123 */
250 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, /* 124 */
251 0x00,0xC0,0x20,0x20,0x20,0x20,0x18,0x20,0x20,0x20,0x20,0xC0,0x00, /* 125 */
252 0x00,0x00,0x48,0xA8,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 126 */
253 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160 */
254 0x00,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, /* 161 */
255 0x00,0x00,0x20,0x70,0xA8,0xA0,0xA0,0xA8,0x70,0x20,0x00,0x00,0x00, /* 162 */
256 0x00,0x00,0x30,0x48,0x40,0x40,0xE0,0x40,0x40,0x48,0xB0,0x00,0x00, /* 163 */
257 0x00,0x00,0x00,0x00,0x88,0x70,0x50,0x50,0x70,0x88,0x00,0x00,0x00, /* 164 */
258 0x00,0x00,0x88,0x88,0x50,0x50,0xF8,0x20,0xF8,0x20,0x20,0x00,0x00, /* 165 */
259 0x00,0x00,0x20,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x20,0x00,0x00, /* 166 */
260 0x00,0x30,0x48,0x40,0x30,0x48,0x48,0x30,0x08,0x48,0x30,0x00,0x00, /* 167 */
261 0x00,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168 */
262 0x00,0x70,0x88,0xA8,0xD8,0xC8,0xD8,0xA8,0x88,0x70,0x00,0x00,0x00, /* 169 */
263 0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0xF8,0x00,0x00,0x00,0x00, /* 170 */
264 0x00,0x00,0x00,0x00,0x28,0x50,0xA0,0xA0,0x50,0x28,0x00,0x00,0x00, /* 171 */
265 0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x08,0x08,0x00,0x00,0x00,0x00, /* 172 */
266 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00, /* 173 */
267 0x00,0x70,0x88,0xE8,0xD8,0xD8,0xE8,0xD8,0x88,0x70,0x00,0x00,0x00, /* 174 */
268 0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 175 */
269 0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176 */
270 0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0xF8,0x00,0x00,0x00, /* 177 */
271 0x00,0x40,0xA0,0x20,0x40,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 178 */
272 0x00,0x40,0xA0,0x40,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 179 */
273 0x00,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 180 */
274 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x98,0xE8,0x80,0x80, /* 181 */
275 0x00,0x00,0x78,0xE8,0xE8,0xE8,0xE8,0x68,0x28,0x28,0x28,0x00,0x00, /* 182 */
276 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00, /* 183 */
277 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20, /* 184 */
278 0x00,0x40,0xC0,0x40,0x40,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 185 */
279 0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0xF8,0x00,0x00,0x00,0x00, /* 186 */
280 0x00,0x00,0x00,0x00,0xA0,0x50,0x28,0x28,0x50,0xA0,0x00,0x00,0x00, /* 187 */
281 0x00,0x40,0xC0,0x40,0x40,0xE0,0x08,0x18,0x28,0x38,0x08,0x00,0x00, /* 188 */
282 0x00,0x40,0xC0,0x40,0x40,0xE0,0x10,0x28,0x08,0x10,0x38,0x00,0x00, /* 189 */
283 0x00,0x40,0xA0,0x40,0x20,0xA0,0x48,0x18,0x28,0x38,0x08,0x00,0x00, /* 190 */
284 0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x80,0x88,0x88,0x70,0x00,0x00, /* 191 */
285 0x00,0x40,0x20,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 192 */
286 0x00,0x10,0x20,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 193 */
287 0x00,0x30,0x48,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 194 */
288 0x00,0x28,0x50,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 195 */
289 0x00,0x50,0x50,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 196 */
290 0x00,0x20,0x50,0x20,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00, /* 197 */
291 0x00,0x00,0x58,0xA0,0xA0,0xA0,0xB0,0xE0,0xA0,0xA0,0xB8,0x00,0x00, /* 198 */
292 0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x80,0x80,0x88,0x70,0x20,0x40, /* 199 */
293 0x00,0x40,0x20,0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00, /* 200 */
294 0x00,0x10,0x20,0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00, /* 201 */
295 0x00,0x30,0x48,0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00, /* 202 */
296 0x00,0x50,0x50,0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00, /* 203 */
297 0x00,0x40,0x20,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 204 */
298 0x00,0x10,0x20,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 205 */
299 0x00,0x30,0x48,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 206 */
300 0x00,0x50,0x50,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 207 */
301 0x00,0x00,0xF0,0x48,0x48,0x48,0xE8,0x48,0x48,0x48,0xF0,0x00,0x00, /* 208 */
302 0x00,0x28,0x50,0x00,0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00,0x00, /* 209 */
303 0x00,0x40,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 210 */
304 0x00,0x10,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 211 */
305 0x00,0x30,0x48,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 212 */
306 0x00,0x28,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 213 */
307 0x00,0x50,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 214 */
308 0x00,0x00,0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00, /* 215 */
309 0x00,0x08,0x70,0x98,0x98,0xA8,0xA8,0xA8,0xC8,0xC8,0x70,0x80,0x00, /* 216 */
310 0x00,0x40,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 217 */
311 0x00,0x10,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 218 */
312 0x00,0x30,0x48,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 219 */
313 0x00,0x50,0x50,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 220 */
314 0x00,0x10,0x20,0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, /* 221 */
315 0x00,0x00,0x80,0xF0,0x88,0x88,0x88,0xF0,0x80,0x80,0x80,0x00,0x00, /* 222 */
316 0x00,0x00,0x60,0x90,0x90,0xA0,0xA0,0x90,0x88,0x88,0xB0,0x00,0x00, /* 223 */
317 0x00,0x00,0x40,0x20,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 224 */
318 0x00,0x00,0x10,0x20,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 225 */
319 0x00,0x00,0x30,0x48,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 226 */
320 0x00,0x00,0x28,0x50,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 227 */
321 0x00,0x00,0x50,0x50,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 228 */
322 0x00,0x30,0x48,0x30,0x00,0x70,0x08,0x78,0x88,0x98,0x68,0x00,0x00, /* 229 */
323 0x00,0x00,0x00,0x00,0x00,0x70,0x28,0x70,0xA0,0xA8,0x50,0x00,0x00, /* 230 */
324 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x88,0x70,0x20,0x40, /* 231 */
325 0x00,0x00,0x40,0x20,0x00,0x70,0x88,0xF8,0x80,0x88,0x70,0x00,0x00, /* 232 */
326 0x00,0x00,0x10,0x20,0x00,0x70,0x88,0xF8,0x80,0x88,0x70,0x00,0x00, /* 233 */
327 0x00,0x00,0x30,0x48,0x00,0x70,0x88,0xF8,0x80,0x88,0x70,0x00,0x00, /* 234 */
328 0x00,0x00,0x50,0x50,0x00,0x70,0x88,0xF8,0x80,0x88,0x70,0x00,0x00, /* 235 */
329 0x00,0x00,0x40,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 236 */
330 0x00,0x00,0x10,0x20,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 237 */
331 0x00,0x00,0x30,0x48,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 238 */
332 0x00,0x00,0x50,0x50,0x00,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, /* 239 */
333 0x00,0x50,0x20,0x60,0x10,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 240 */
334 0x00,0x00,0x28,0x50,0x00,0xB0,0xC8,0x88,0x88,0x88,0x88,0x00,0x00, /* 241 */
335 0x00,0x00,0x40,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 242 */
336 0x00,0x00,0x10,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 243 */
337 0x00,0x00,0x30,0x48,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 244 */
338 0x00,0x00,0x28,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 245 */
339 0x00,0x00,0x50,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, /* 246 */
340 0x00,0x00,0x00,0x20,0x20,0x00,0xF8,0x00,0x20,0x20,0x00,0x00,0x00, /* 247 */
341 0x00,0x00,0x00,0x00,0x08,0x70,0x98,0xA8,0xA8,0xC8,0x70,0x80,0x00, /* 248 */
342 0x00,0x00,0x40,0x20,0x00,0x88,0x88,0x88,0x88,0x98,0x68,0x00,0x00, /* 249 */
343 0x00,0x00,0x10,0x20,0x00,0x88,0x88,0x88,0x88,0x98,0x68,0x00,0x00, /* 250 */
344 0x00,0x00,0x30,0x48,0x00,0x88,0x88,0x88,0x88,0x98,0x68,0x00,0x00, /* 251 */
345 0x00,0x00,0x50,0x50,0x00,0x88,0x88,0x88,0x88,0x98,0x68,0x00,0x00, /* 252 */
346 0x00,0x00,0x10,0x20,0x00,0x88,0x88,0x88,0x98,0x68,0x08,0x88,0x70, /* 253 */
347 0x00,0x00,0x00,0x80,0x80,0xB0,0xC8,0x88,0x88,0xC8,0xB0,0x80,0x80, /* 254 */
348 0x00,0x00,0x50,0x50,0x00,0x88,0x88,0x88,0x98,0x68,0x08,0x88,0x70, /* 255 */
349 };
350 static int default6x13FontMetaData[256*5]={
351 0,6,13,0,-2,13,6,13,0,-2,26,6,13,0,-2,39,6,13,0,-2,52,6,13,0,-2,65,6,13,0,-2,78,6,13,0,-2,91,6,13,0,-2,104,6,13,0,-2,117,6,13,0,-2,130,6,13,0,-2,143,6,13,0,-2,156,6,13,0,-2,169,6,13,0,-2,182,6,13,0,-2,195,6,13,0,-2,208,6,13,0,-2,221,6,13,0,-2,234,6,13,0,-2,247,6,13,0,-2,260,6,13,0,-2,273,6,13,0,-2,286,6,13,0,-2,299,6,13,0,-2,312,6,13,0,-2,325,6,13,0,-2,338,6,13,0,-2,351,6,13,0,-2,364,6,13,0,-2,377,6,13,0,-2,390,6,13,0,-2,403,6,13,0,-2,416,6,13,0,-2,429,6,13,0,-2,442,6,13,0,-2,455,6,13,0,-2,468,6,13,0,-2,481,6,13,0,-2,494,6,13,0,-2,507,6,13,0,-2,520,6,13,0,-2,533,6,13,0,-2,546,6,13,0,-2,559,6,13,0,-2,572,6,13,0,-2,585,6,13,0,-2,598,6,13,0,-2,611,6,13,0,-2,624,6,13,0,-2,637,6,13,0,-2,650,6,13,0,-2,663,6,13,0,-2,676,6,13,0,-2,689,6,13,0,-2,702,6,13,0,-2,715,6,13,0,-2,728,6,13,0,-2,741,6,13,0,-2,754,6,13,0,-2,767,6,13,0,-2,780,6,13,0,-2,793,6,13,0,-2,806,6,13,0,-2,819,6,13,0,-2,832,6,13,0,-2,845,6,13,0,-2,858,6,13,0,-2,871,6,13,0,-2,884,6,13,0,-2,897,6,13,0,-2,910,6,13,0,-2,923,6,13,0,-2,936,6,13,0,-2,949,6,13,0,-2,962,6,13,0,-2,975,6,13,0,-2,988,6,13,0,-2,1001,6,13,0,-2,1014,6,13,0,-2,1027,6,13,0,-2,1040,6,13,0,-2,1053,6,13,0,-2,1066,6,13,0,-2,1079,6,13,0,-2,1092,6,13,0,-2,1105,6,13,0,-2,1118,6,13,0,-2,1131,6,13,0,-2,1144,6,13,0,-2,1157,6,13,0,-2,1170,6,13,0,-2,1183,6,13,0,-2,1196,6,13,0,-2,1209,6,13,0,-2,1222,6,13,0,-2,1235,6,13,0,-2,1248,6,13,0,-2,1261,6,13,0,-2,1274,6,13,0,-2,1287,6,13,0,-2,1300,6,13,0,-2,1313,6,13,0,-2,1326,6,13,0,-2,1339,6,13,0,-2,1352,6,13,0,-2,1365,6,13,0,-2,1378,6,13,0,-2,1391,6,13,0,-2,1404,6,13,0,-2,1417,6,13,0,-2,1430,6,13,0,-2,1443,6,13,0,-2,1456,6,13,0,-2,1469,6,13,0,-2,1482,6,13,0,-2,1495,6,13,0,-2,1508,6,13,0,-2,1521,6,13,0,-2,1534,6,13,0,-2,1547,6,13,0,-2,1560,6,13,0,-2,1573,6,13,0,-2,1586,6,13,0,-2,1599,6,13,0,-2,1612,6,13,0,-2,1625,6,13,0,-2,1638,6,13,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1651,6,13,0,-2,1664,6,13,0,-2,1677,6,13,0,-2,1690,6,13,0,-2,1703,6,13,0,-2,1716,6,13,0,-2,1729,6,13,0,-2,1742,6,13,0,-2,1755,6,13,0,-2,1768,6,13,0,-2,1781,6,13,0,-2,1794,6,13,0,-2,1807,6,13,0,-2,1820,6,13,0,-2,1833,6,13,0,-2,1846,6,13,0,-2,1859,6,13,0,-2,1872,6,13,0,-2,1885,6,13,0,-2,1898,6,13,0,-2,1911,6,13,0,-2,1924,6,13,0,-2,1937,6,13,0,-2,1950,6,13,0,-2,1963,6,13,0,-2,1976,6,13,0,-2,1989,6,13,0,-2,2002,6,13,0,-2,2015,6,13,0,-2,2028,6,13,0,-2,2041,6,13,0,-2,2054,6,13,0,-2,2067,6,13,0,-2,2080,6,13,0,-2,2093,6,13,0,-2,2106,6,13,0,-2,2119,6,13,0,-2,2132,6,13,0,-2,2145,6,13,0,-2,2158,6,13,0,-2,2171,6,13,0,-2,2184,6,13,0,-2,2197,6,13,0,-2,2210,6,13,0,-2,2223,6,13,0,-2,2236,6,13,0,-2,2249,6,13,0,-2,2262,6,13,0,-2,2275,6,13,0,-2,2288,6,13,0,-2,2301,6,13,0,-2,2314,6,13,0,-2,2327,6,13,0,-2,2340,6,13,0,-2,2353,6,13,0,-2,2366,6,13,0,-2,2379,6,13,0,-2,2392,6,13,0,-2,2405,6,13,0,-2,2418,6,13,0,-2,2431,6,13,0,-2,2444,6,13,0,-2,2457,6,13,0,-2,2470,6,13,0,-2,2483,6,13,0,-2,2496,6,13,0,-2,2509,6,13,0,-2,2522,6,13,0,-2,2535,6,13,0,-2,2548,6,13,0,-2,2561,6,13,0,-2,2574,6,13,0,-2,2587,6,13,0,-2,2600,6,13,0,-2,2613,6,13,0,-2,2626,6,13,0,-2,2639,6,13,0,-2,2652,6,13,0,-2,2665,6,13,0,-2,2678,6,13,0,-2,2691,6,13,0,-2,2704,6,13,0,-2,2717,6,13,0,-2,2730,6,13,0,-2,2743,6,13,0,-2,2756,6,13,0,-2,2769,6,13,0,-2,2782,6,13,0,-2,2795,6,13,0,-2,2808,6,13,0,-2,2821,6,13,0,-2,2834,6,13,0,-2,2847,6,13,0,-2,2860,6,13,0,-2,2873,6,13,0,-2,2886,6,13,0,-2,};
352 static rfbFontData default6x13Font={default6x13FontData, default6x13FontMetaData};
353 
354 static int in_login = 0, in_passwd = 0, tries = 0;
355 static int char_row = 0, char_col = 0;
356 static int char_x = 0, char_y = 0, char_w = 8, char_h = 16;
357 
358 static int db = 0;
359 
white_pixel(void)360 int white_pixel(void) {
361 	static unsigned long black_pix = 0, white_pix = 1, set = 0;
362 
363 	RAWFB_RET(0xffffff)
364 
365 	if (depth <= 8 && ! set) {
366 		X_LOCK;
367 		black_pix = BlackPixel(dpy, scr);
368 		white_pix = WhitePixel(dpy, scr);
369 		X_UNLOCK;
370 		set = 1;
371 	}
372 	if (depth <= 8) {
373 		return (int) white_pix;
374 	} else if (depth < 24) {
375 		return 0xffff;
376 	} else {
377 		return 0xffffff;
378 	}
379 }
380 
black_pixel(void)381 int black_pixel(void) {
382 	static unsigned long black_pix = 0, white_pix = 1, set = 0;
383 
384 	RAWFB_RET(0x000000)
385 
386 	if (depth <= 8 && ! set) {
387 		X_LOCK;
388 		black_pix = BlackPixel(dpy, scr);
389 		white_pix = WhitePixel(dpy, scr);
390 		X_UNLOCK;
391 		set = 1;
392 	}
393 	if (depth <= 8) {
394 		return (int) black_pix;
395 	} else if (depth < 24) {
396 		return 0x0000;
397 	} else {
398 		return 0x000000;
399 	}
400 }
401 
unixpw_mark(void)402 static void unixpw_mark(void) {
403 	if (scaling) {
404 		mark_rect_as_modified(0, 0, scaled_x, scaled_y, 1);
405 	} else {
406 		mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
407 	}
408 }
409 
text_x(void)410 static int text_x(void) {
411 	return char_x + char_col * char_w;
412 }
413 
text_y(void)414 static int text_y(void) {
415 	return char_y + char_row * char_h;
416 }
417 
418 static rfbScreenInfo fscreen;
419 static rfbScreenInfoPtr pscreen;
420 
421 static int f1_help = 0;
422 
unixpw_screen(int init)423 void unixpw_screen(int init) {
424 	if (unixpw_cmd) {
425 		;	/* OK */
426 	} else if (unixpw_nis) {
427 #ifndef UNIXPW_CRYPT
428 	rfbLog("-unixpw_nis is not supported on this OS/machine\n");
429 	clean_up_exit(1);
430 #endif
431 	} else {
432 #ifndef UNIXPW_SU
433 	rfbLog("-unixpw is not supported on this OS/machine\n");
434 	clean_up_exit(1);
435 #endif
436 	}
437 	if (init) {
438 		int x, y;
439 		char log[] = "login: ";
440 
441 		zero_fb(0, 0, dpy_x, dpy_y);
442 
443 		mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
444 
445 		x = nfix(dpy_x / 2 -  strlen(log) * char_w, dpy_x);
446 		y = (int) (dpy_y / 3.5);
447 		if (unixpw_system_greeter) {
448 			y = (int) (dpy_y / 3);
449 		}
450 
451 		if (scaling) {
452 			x = (int) (x * scale_fac_x);
453 			y = (int) (y * scale_fac_y);
454 			x = nfix(x, scaled_x);
455 			y = nfix(y, scaled_y);
456 		}
457 
458 		if (rotating) {
459 			fscreen.serverFormat.bitsPerPixel = bpp;
460 			fscreen.paddedWidthInBytes = rfb_bytes_per_line;
461 			fscreen.frameBuffer = rfb_fb;
462 			pscreen = &fscreen;
463 		} else {
464 			pscreen = screen;
465 		}
466 
467 		if (pscreen && pscreen->width >= 640 && pscreen->height >= 480) {
468 			rfbDrawString(pscreen, &default6x13Font, 8, 2+1*13, "F1-Help:", white_pixel());
469 		}
470 		f1_help = 0;
471 
472 		if (unixpw_system_greeter) {
473 			unixpw_system_greeter_active = 0;
474 			if (use_dpy && strstr(use_dpy, "xdmcp")) {
475 				if (getenv("X11VNC_SYSTEM_GREETER1")) {
476 					char moo[] = "Press 'Escape' for System Greeter";
477 					rfbDrawString(pscreen, &default8x16Font, x-90, y-30, moo, white_pixel());
478 				} else {
479 					char moo1[] = "Press 'Escape' for a New Session via System Greeter, or";
480 					char moo2[] = "otherwise login here to connect to an Existing Session:";
481 					rfbDrawString(pscreen, &default6x13Font, x-110, y-38, moo1, white_pixel());
482 					rfbDrawString(pscreen, &default6x13Font, x-110, y-25, moo2, white_pixel());
483 				}
484 				set_env("X11VNC_XDM_ONLY", "0");
485 				unixpw_system_greeter_active = 1;
486 			}
487 		}
488 
489 		rfbDrawString(pscreen, &default8x16Font, x, y, log, white_pixel());
490 
491 		char_x = x;
492 		char_y = y;
493 		char_col = strlen(log);
494 		char_row = 0;
495 
496 		set_warrow_cursor();
497 	}
498 
499 	unixpw_mark();
500 }
501 
502 
503 #ifdef MAXPATHLEN
504 static char slave_str[MAXPATHLEN];
505 #else
506 static char slave_str[4096];
507 #endif
508 
509 static int used_get_pty_ptmx = 0;
510 
get_pty_ptmx(int * fd_p)511 char *get_pty_ptmx(int *fd_p) {
512 	char *slave;
513 	int fd = -1, i, ndevs = 4, tmp;
514 	char *devs[] = {
515 		"/dev/ptmx",
516 		"/dev/ptm/clone",
517 		"/dev/ptc",
518 		"/dev/ptmx_bsd"
519 	};
520 
521 	*fd_p = -1;
522 
523 #if LIBVNCSERVER_HAVE_GRANTPT
524 
525 	for (i=0; i < ndevs; i++) {
526 #ifdef O_NOCTTY
527 		fd = open(devs[i], O_RDWR|O_NOCTTY);
528 #else
529 		fd = open(devs[i], O_RDWR);
530 #endif
531 		if (fd >= 0) {
532 			break;
533 		}
534 	}
535 
536 	if (fd < 0) {
537 		rfbLogPerror("open /dev/ptmx");
538 		return NULL;
539 	}
540 
541 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCPKT)
542 	tmp = 0;
543 	ioctl(fd, TIOCPKT, (char *) &tmp);
544 #endif
545 
546 	if (grantpt(fd) != 0) {
547 		rfbLogPerror("grantpt");
548 		close(fd);
549 		return NULL;
550 	}
551 	if (unlockpt(fd) != 0) {
552 		rfbLogPerror("unlockpt");
553 		close(fd);
554 		return NULL;
555 	}
556 
557 	slave = ptsname(fd);
558 	if (! slave)  {
559 		rfbLogPerror("ptsname");
560 		close(fd);
561 		return NULL;
562 	}
563 
564 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCFLUSH)
565 	ioctl(fd, TIOCFLUSH, (char *) 0);
566 #endif
567 
568 	if (strlen(slave) > sizeof(slave_str)/2) {
569 		rfbLog("get_pty_ptmx: slave string length too long.\n");
570 		close(fd);
571 		return NULL;
572 	}
573 
574 	strcpy(slave_str, slave);
575 	*fd_p = fd;
576 	return slave_str;
577 
578 #else
579 	return NULL;
580 
581 #endif /* GRANTPT */
582 }
583 
584 
get_pty_loop(int * fd_p)585 char *get_pty_loop(int *fd_p) {
586 	char master_str[16];
587 	int fd = -1, i;
588 	char c;
589 
590 	*fd_p = -1;
591 
592 	/* for *BSD loop over /dev/ptyXY */
593 
594 	for (c = 'p'; c <= 'z'; c++) {
595 		for (i=0; i < 16; i++) {
596 			sprintf(master_str, "/dev/pty%c%x", c, i);
597 #ifdef O_NOCTTY
598 			fd = open(master_str, O_RDWR|O_NOCTTY);
599 #else
600 			fd = open(master_str, O_RDWR);
601 #endif
602 			if (fd >= 0) {
603 				break;
604 			}
605 		}
606 		if (fd >= 0) {
607 			break;
608 		}
609 	}
610 	if (fd < 0) {
611 		return NULL;
612 	}
613 
614 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCFLUSH)
615 	ioctl(fd, TIOCFLUSH, (char *) 0);
616 #endif
617 
618 	sprintf(slave_str, "/dev/tty%c%x", c, i);
619 	*fd_p = fd;
620 	return slave_str;
621 }
622 
get_pty(int * fd_p)623 char *get_pty(int *fd_p) {
624 	used_get_pty_ptmx = 0;
625 	if (getenv("BSD_PTY")) {
626 		return get_pty_loop(fd_p);
627 	}
628 #ifdef IS_BSD
629 	return get_pty_loop(fd_p);
630 #else
631 #if LIBVNCSERVER_HAVE_GRANTPT
632 	used_get_pty_ptmx = 1;
633 	return get_pty_ptmx(fd_p);
634 #else
635 	return get_pty_loop(fd_p);
636 #endif
637 #endif
638 }
639 
try_to_be_nobody(void)640 void try_to_be_nobody(void) {
641 
642 #if LIBVNCSERVER_HAVE_PWD_H
643 	struct passwd *pw;
644 	pw = getpwnam("nobody");
645 
646 	if (pw) {
647 #if LIBVNCSERVER_HAVE_SETUID
648 		setuid(pw->pw_uid);
649 #endif
650 #if LIBVNCSERVER_HAVE_SETEUID
651 		seteuid(pw->pw_uid);
652 #endif
653 #if LIBVNCSERVER_HAVE_SETGID
654 		setgid(pw->pw_gid);
655 #endif
656 #if LIBVNCSERVER_HAVE_SETEGID
657 		setegid(pw->pw_gid);
658 #endif
659 	}
660 #endif	/* PWD_H */
661 }
662 
663 
664 static int slave_fd = -1, alarm_fired = 0;
665 
close_alarm(int sig)666 static void close_alarm (int sig) {
667 	if (slave_fd >= 0) {
668 		close(slave_fd);
669 	}
670 	alarm_fired = 1;
671 	if (0) sig = 0;	/* compiler warning */
672 }
673 
kill_child(pid_t pid,int fd)674 static void kill_child (pid_t pid, int fd) {
675 	int status;
676 
677 	slave_fd = -1;
678 	alarm_fired = 0;
679 	if (fd >= 0) {
680 		close(fd);
681 	}
682 	kill(pid, SIGTERM);
683 	waitpid(pid, &status, WNOHANG);
684 }
685 
scheck(char * str,int n,char * name)686 static int scheck(char *str, int n, char *name) {
687 	int j, i;
688 
689 	if (! str) {
690 		return 0;
691 	}
692 	j = 0;
693 	for (i=0; i<n; i++) {
694 		if (str[i] == '\0') {
695 			j = 1;
696 			break;
697 		}
698 		if (!strcmp(name, "password")) {
699 			if (str[i] == '\n') {
700 				continue;
701 			}
702 		}
703 		if (str[i] < ' ' || str[i] >= 0x7f) {
704 			rfbLog("scheck: invalid character in %s.\n", name);
705 			return 0;
706 		}
707 	}
708 	if (j == 0) {
709 		rfbLog("scheck: unterminated string in %s.\n", name);
710 		return 0;
711 	}
712 	return 1;
713 }
714 
unixpw_list_match(char * user)715 int unixpw_list_match(char *user) {
716 	if (! unixpw_list || unixpw_list[0] == '\0') {
717 		return 1;
718 	} else {
719 		char *p, *q, *str = strdup(unixpw_list);
720 		int ok = 0;
721 		int notmode = 0;
722 
723 		if (str[0] == '!') {
724 			notmode = 1;
725 			ok = 1;
726 			p = strtok(str+1, ",");
727 		} else {
728 			p = strtok(str, ",");
729 		}
730 		while (p) {
731 			if ( (q = strchr(p, ':')) != NULL ) {
732 				*q = '\0';	/* get rid of options. */
733 			}
734 			if (!strcmp(user, p)) {
735 				if (notmode) {
736 					ok = 0;
737 				} else {
738 					ok = 1;
739 				}
740 				break;
741 			}
742 			if (!notmode && !strcmp("*", p)) {
743 				ok = 1;
744 				break;
745 			}
746 			p = strtok(NULL, ",");
747 		}
748 		free(str);
749 		if (! ok) {
750 			rfbLog("unixpw_list_match: fail for '%s'\n", user);
751 			return 0;
752 		} else {
753 			rfbLog("unixpw_list_match: OK for '%s'\n", user);
754 			return 1;
755 		}
756 	}
757 }
758 
crypt_verify(char * user,char * pass)759 int crypt_verify(char *user, char *pass) {
760 #ifndef UNIXPW_CRYPT
761 	return 0;
762 #else
763 	struct passwd *pwd;
764 	char *realpw, *cr;
765 	int n;
766 
767 	if (! scheck(user, 100, "username")) {
768 		return 0;
769 	}
770 	if (! scheck(pass, 100, "password")) {
771 		return 0;
772 	}
773 	if (! unixpw_list_match(user)) {
774 		return 0;
775 	}
776 
777 	pwd = getpwnam(user);
778 	if (! pwd) {
779 		return 0;
780 	}
781 
782 	realpw = pwd->pw_passwd;
783 	if (realpw == NULL || realpw[0] == '\0') {
784 		return 0;
785 	}
786 
787 	if (db > 1) fprintf(stderr, "realpw='%s'\n", realpw);
788 
789 	if (strlen(realpw) < 12) {
790 		/* e.g. "x", try getspnam(), sometimes root for inetd, etc */
791 #if LIBVNCSERVER_HAVE_GETSPNAM
792 		struct spwd *sp = getspnam(user);
793 		if (sp != NULL && sp->sp_pwdp != NULL) {
794 			if (db) fprintf(stderr, "using getspnam()\n");
795 			realpw = sp->sp_pwdp;
796 		} else {
797 			if (db) fprintf(stderr, "skipping getspnam()\n");
798 		}
799 #endif
800 	}
801 
802 	n = strlen(pass);
803 	if (pass[n-1] == '\n') {
804 		pass[n-1] = '\0';
805 	}
806 
807 	/* XXX remove need for cast */
808 	cr = (char *) crypt(pass, realpw);
809 	if (db > 1) {
810 		fprintf(stderr, "user='%s' pass='%s' realpw='%s' cr='%s'\n",
811 		    user, pass, realpw, cr ? cr : "(null)");
812 	}
813 	if (cr == NULL || cr[0] == '\0') {
814 		return 0;
815 	}
816 	if (!strcmp(cr, realpw)) {
817 		return 1;
818 	} else {
819 		return 0;
820 	}
821 #endif	/* UNIXPW_CRYPT */
822 }
823 
unixpw_cmd_run(char * user,char * pass,char * cmd,char * line,int * n)824 int unixpw_cmd_run(char *user, char *pass, char *cmd, char *line, int *n) {
825 	int i, len, rc;
826 	char *str;
827 	FILE *out;
828 
829 	if (! user || ! pass) {
830 		return 0;
831 	}
832 	if (! unixpw_cmd || *unixpw_cmd == '\0') {
833 		return 0;
834 	}
835 
836 	if (! scheck(user, 100, "username")) {
837 		return 0;
838 	}
839 	if (! scheck(pass, 100, "password")) {
840 		return 0;
841 	}
842 	if (! unixpw_list_match(user)) {
843 		return 0;
844 	}
845 	if (cmd == NULL) {
846 		cmd = "";
847 	}
848 
849 	len = strlen(user) + 1 + strlen(pass) + 1 + 1;
850 	str = (char *) malloc(len);
851 	if (! str) {
852 		return 0;
853 	}
854 	str[0] = '\0';
855 	strcat(str, user);
856 	strcat(str, "\n");
857 	strcat(str, pass);
858 	if (!strchr(pass, '\n')) {
859 		strcat(str, "\n");
860 	}
861 
862 	out = tmpfile();
863 	if (out == NULL) {
864 		rfbLog("unixpw_cmd_run tmpfile() failed.\n");
865 		clean_up_exit(1);
866 	}
867 
868 	set_env("RFB_UNIXPW_CMD_RUN", cmd);
869 
870 	rc = run_user_command(unixpw_cmd, unixpw_client, "cmd_verify",
871 	    str, strlen(str), out);
872 
873 	set_env("RFB_UNIXPW_CMD_RUN", "");
874 
875 	for (i=0; i < len; i++) {
876 		str[i] = '\0';
877 	}
878 	free(str);
879 
880 	fflush(out);
881 	rewind(out);
882 	for (i=0; i < (*n) - 1; i++) {
883 		int c = fgetc(out);
884 		if (c == EOF) {
885 			break;
886 		}
887 		line[i] = (char) c;
888 	}
889 	fclose(out);
890 	*n = i;
891 
892 	if (rc == 0) {
893 		return 1;
894 	} else {
895 		return 0;
896 	}
897 }
898 
899 
cmd_verify(char * user,char * pass)900 int cmd_verify(char *user, char *pass) {
901 	int i, len, rc;
902 	char *str;
903 
904 	if (! user || ! pass) {
905 		return 0;
906 	}
907 	if (! unixpw_cmd || *unixpw_cmd == '\0') {
908 		return 0;
909 	}
910 
911 	if (! scheck(user, 100, "username")) {
912 		return 0;
913 	}
914 	if (! scheck(pass, 100, "password")) {
915 		return 0;
916 	}
917 	if (! unixpw_list_match(user)) {
918 		return 0;
919 	}
920 
921 	if (unixpw_client) {
922 		ClientData *cd = (ClientData *) unixpw_client->clientData;
923 		if (cd) {
924 			cd->username = strdup(user);
925 		}
926 	}
927 
928 	len = strlen(user) + 1 + strlen(pass) + 1 + 1;
929 	str = (char *) malloc(len);
930 	if (! str) {
931 		return 0;
932 	}
933 	str[0] = '\0';
934 	strcat(str, user);
935 	strcat(str, "\n");
936 	strcat(str, pass);
937 	if (!strchr(pass, '\n')) {
938 		strcat(str, "\n");
939 	}
940 
941 	rc = run_user_command(unixpw_cmd, unixpw_client, "cmd_verify",
942 	    str, strlen(str), NULL);
943 
944 	for (i=0; i < len; i++) {
945 		str[i] = '\0';
946 	}
947 	free(str);
948 
949 	if (rc == 0) {
950 		return 1;
951 	} else {
952 		return 0;
953 	}
954 }
955 
su_verify(char * user,char * pass,char * cmd,char * rbuf,int * rbuf_size,int nodisp)956 int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp) {
957 #ifndef UNIXPW_SU
958 	return 0;
959 #else
960 	int i, j, status, fd = -1, sfd, tfd, drain_size = 65536, rsize = 0;
961 	int slow_pw = 1;
962 	char *slave, *bin_true = NULL, *bin_su = NULL;
963 	pid_t pid, pidw;
964 	struct stat sbuf;
965 	static int first = 1;
966 	char instr[64], cbuf[10];
967 
968 	if (first) {
969 		set_db();
970 		first = 0;
971 	}
972 	rfbLog("su_verify: '%s' for %s.\n", user, cmd ? "command" : "login");
973 	fflush(stderr);
974 
975 	if (! scheck(user, 100, "username")) {
976 		return 0;
977 	}
978 	if (! scheck(pass, 100, "password")) {
979 		return 0;
980 	}
981 	if (! unixpw_list_match(user)) {
982 		return 0;
983 	}
984 
985 	/* unixpw */
986 	if (no_external_cmds || !cmd_ok("unixpw")) {
987 		rfbLog("su_verify: cannot run external commands.\n");
988 		clean_up_exit(1);
989 	}
990 
991 #define SU_DEBUG 0
992 #if SU_DEBUG
993 	if (stat("/su", &sbuf) == 0) {
994 		bin_su = "/su";	/* Freesbie read-only-fs /bin/su not suid! */
995 #else
996 	if (0) {
997 		;
998 #endif
999 	} else if (stat("/bin/su", &sbuf) == 0) {
1000 		bin_su = "/bin/su";
1001 	} else if (stat("/usr/bin/su", &sbuf) == 0) {
1002 		bin_su = "/usr/bin/su";
1003 	}
1004 	if (bin_su == NULL) {
1005 		rfbLogPerror("existence /bin/su");
1006 		fflush(stderr);
1007 		return 0;
1008 	}
1009 
1010 	if (stat("/bin/true", &sbuf) == 0) {
1011 		bin_true = "/bin/true";
1012 	} if (stat("/usr/bin/true", &sbuf) == 0) {
1013 		bin_true = "/usr/bin/true";
1014 	}
1015 	if (cmd != NULL && cmd[0] != '\0') {
1016 		/* this is for ext. cmd su -c "my cmd" after login */
1017 		bin_true = cmd;
1018 	}
1019 	if (bin_true == NULL) {
1020 		rfbLogPerror("existence /bin/true");
1021 		fflush(stderr);
1022 		return 0;
1023 	}
1024 
1025 	slave = get_pty(&fd);
1026 
1027 	if (slave == NULL) {
1028 		rfbLogPerror("get_pty failed.");
1029 		fflush(stderr);
1030 		return 0;
1031 	}
1032 
1033 	if (db) fprintf(stderr, "cmd is: %s\n", cmd);
1034 	if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
1035 
1036 	if (fd < 0) {
1037 		rfbLogPerror("get_pty fd < 0");
1038 		fflush(stderr);
1039 		return 0;
1040 	}
1041 
1042 	fcntl(fd, F_SETFD, 1);
1043 
1044 	pid = fork();
1045 	if (pid < 0) {
1046 		rfbLogPerror("fork");
1047 		fflush(stderr);
1048 		close(fd);
1049 		return 0;
1050 	}
1051 
1052 	if (pid == 0) {
1053 		/* child */
1054 
1055 		int ttyfd;
1056 		ttyfd = -1;	/* compiler warning */
1057 
1058 #if LIBVNCSERVER_HAVE_SETSID
1059 		if (setsid() == -1) {
1060 			perror("setsid");
1061 			exit(1);
1062 		}
1063 #else
1064 		if (setpgrp() == -1) {
1065 			perror("setpgrp");
1066 			exit(1);
1067 		}
1068 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCNOTTY)
1069 		ttyfd = open("/dev/tty", O_RDWR);
1070 		if (ttyfd >= 0) {
1071 			(void) ioctl(ttyfd, TIOCNOTTY, (char *) 0);
1072 			close(ttyfd);
1073 		}
1074 #endif
1075 
1076 #endif	/* SETSID */
1077 
1078 		close(0);
1079 		close(1);
1080 		close(2);
1081 
1082 		sfd = open(slave, O_RDWR);
1083 		if (sfd < 0) {
1084 			exit(1);
1085 		}
1086 
1087 /* streams options fixups, handle cases as they are found: */
1088 #if defined(__hpux)
1089 #if LIBVNCSERVER_HAVE_SYS_STROPTS_H
1090 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(I_PUSH)
1091 		if (used_get_pty_ptmx) {
1092 			ioctl(sfd, I_PUSH, "ptem");
1093 			ioctl(sfd, I_PUSH, "ldterm");
1094 			ioctl(sfd, I_PUSH, "ttcompat");
1095 		}
1096 #endif
1097 #endif
1098 #endif
1099 
1100 		/* n.b. sfd will be 0 since we closed 0. so dup it to 1 and 2 */
1101 		if (fcntl(sfd, F_DUPFD, 1) == -1) {
1102 			exit(1);
1103 		}
1104 		if (fcntl(sfd, F_DUPFD, 2) == -1) {
1105 			exit(1);
1106 		}
1107 
1108 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCSCTTY)
1109 		ioctl(sfd, TIOCSCTTY, (char *) 0);
1110 #endif
1111 
1112 		if (db > 2) {
1113 			char nam[256];
1114 			unlink("/tmp/isatty");
1115 			tfd = open("/tmp/isatty", O_CREAT|O_WRONLY, 0600);
1116 			if (isatty(sfd)) {
1117 				close(tfd);
1118 				sprintf(nam, "stty -a < %s > /tmp/isatty 2>&1",
1119 				    slave);
1120 				system(nam);
1121 			} else {
1122 				write(tfd, "NOTTTY\n", 7);
1123 				close(tfd);
1124 			}
1125 		}
1126 
1127 		chdir("/");
1128 
1129 		try_to_be_nobody();
1130 #if LIBVNCSERVER_HAVE_GETUID
1131 		if (getuid() == 0 || geteuid() == 0) {
1132 			exit(1);
1133 		}
1134 #else
1135 		exit(1);
1136 #endif
1137 
1138 		set_env("LC_ALL", "C");
1139 		set_env("LANG", "C");
1140 		set_env("SHELL", "/bin/sh");
1141 		if (nodisp) {
1142 			/* this will cause timeout problems with pam_xauth */
1143 			int k;
1144 			for (k=0; k<3; k++) {
1145 				if (getenv("DISPLAY")) {
1146 					char *s = getenv("DISPLAY");
1147 					if (s) *(s-2) = '_';	/* quite... */
1148 				}
1149 				if (getenv("XAUTHORITY")) {
1150 					char *s = getenv("XAUTHORITY");
1151 					if (s) *(s-2) = '_';	/* quite... */
1152 				}
1153 			}
1154 		}
1155 
1156 		/* synchronize with parent: */
1157 		write(2, "C", 1);
1158 
1159 		if (cmd) {
1160 			execlp(bin_su, bin_su, "-", user, "-c",
1161 			    bin_true, (char *) NULL);
1162 		} else {
1163 			execlp(bin_su, bin_su, user, "-c",
1164 			    bin_true, (char *) NULL);
1165 		}
1166 		exit(1);
1167 	}
1168 	/* parent */
1169 
1170 	if (db)	fprintf(stderr, "pid: %d\n", pid);
1171 
1172 	/*
1173 	 * set an alarm for blocking read() to close the master
1174 	 * (presumably terminating the child. SIGTERM too...)
1175 	 */
1176 	slave_fd = fd;
1177 	alarm_fired = 0;
1178 	signal(SIGALRM, close_alarm);
1179 	alarm(10);
1180 
1181 	/* synchronize with child: */
1182 	cbuf[0] = '\0';
1183 	cbuf[1] = '\0';
1184 	for (i=0; i<10; i++) {
1185 		int n;
1186 		cbuf[0] = '\0';
1187 		cbuf[1] = '\0';
1188 		n = read(fd, cbuf, 1);
1189 		if (n < 0 && errno == EINTR) {
1190 			continue;
1191 		} else {
1192 			break;
1193 		}
1194 	}
1195 
1196 	if (db) {
1197 		fprintf(stderr, "read from child: '%s'\n", cbuf);
1198 	}
1199 
1200 	alarm(0);
1201 	signal(SIGALRM, SIG_DFL);
1202 	if (alarm_fired) {
1203 		kill_child(pid, fd);
1204 		return 0;
1205 	}
1206 
1207 #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCTRAP)
1208 	{
1209 		int control = 1;
1210 		ioctl(fd, TIOCTRAP, &control);
1211 	}
1212 #endif
1213 
1214 	/*
1215 	 * In addition to checking exit code below, we watch for the
1216 	 * appearance of the string "Password:".  BSD does not seem to
1217 	 * ask for a password trying to su to yourself.  This is the
1218 	 * setting in /etc/pam.d/su:
1219 	 * 	auth      sufficient  pam_self.so
1220 	 * it may be commented out without problem.
1221 	 */
1222 	for (i=0; i< (int) sizeof(instr); i++) {
1223 		instr[i] = '\0';
1224 	}
1225 
1226 	alarm_fired = 0;
1227 	signal(SIGALRM, close_alarm);
1228 	alarm(10);
1229 
1230 	j = 0;
1231 	for (i=0; i < (int) strlen("Password:"); i++) {
1232 		char pstr[] = "password:";
1233 		int n, problem;
1234 
1235 		cbuf[0] = '\0';
1236 		cbuf[1] = '\0';
1237 
1238 		n = read(fd, cbuf, 1);
1239 		if (n < 0 && errno == EINTR) {
1240 			i--;
1241 			if (i < -1) i = -1;
1242 			continue;
1243 		}
1244 
1245 		if (db) {
1246 			fprintf(stderr, "%s", cbuf);
1247 			if (db > 3 && n == 1 && cbuf[0] == ':') {
1248 				char cmd0[32];
1249 				usleep( 100 * 1000 );
1250 				fprintf(stderr, "\n\n");
1251 				sprintf(cmd0, "ps wu %d", pid);
1252 				system(cmd0);
1253 				sprintf(cmd0, "stty -a < %s", slave);
1254 				system(cmd0);
1255 				fprintf(stderr, "\n\n");
1256 			}
1257 		}
1258 
1259 		if (n == 1) {
1260 			if (isspace((unsigned char) cbuf[0])) {
1261 				i--;
1262 				if (i < -1) i = -1;
1263 				continue;
1264 			}
1265 			if (j >= (int) sizeof(instr)-1) {
1266 				rfbLog("su_verify: problem finding Password:\n");
1267 				fflush(stderr);
1268 				return 0;
1269 			}
1270 			instr[j++] = tolower((unsigned char)cbuf[0]);
1271 		}
1272 
1273 		problem = 0;
1274 		if (n <= 0) {
1275 			problem = 1;
1276 		} else if (strstr(pstr, instr) != pstr) {
1277 #ifdef _AIX
1278 			if (UT.sysname && strstr(UT.sysname, "AIX")) {
1279 				/* handle: runge's Password: */
1280 				char *luser = (char *) malloc(strlen(user) + 10);
1281 
1282 				sprintf(luser, "%s's", user);
1283 				lowercase(luser);
1284 				if (db) fprintf(stderr, "\nAIX luser compare: \"%s\" to \"%s\"\n", luser, instr);
1285 				if (strstr(luser, instr) == luser) {
1286 					if (db) fprintf(stderr, "AIX luser compare: strstr OK.\n");
1287 					if (!strcmp(luser, instr)) {
1288 						if (db) fprintf(stderr, "AIX luser compare: strings equal.\n");
1289 						i = -1;
1290 						j = 0;
1291 						memset(instr, 0, sizeof(instr));
1292 						free(luser);
1293 						continue;
1294 					} else {
1295 						i--;
1296 						if (i < -1) i = -1;
1297 						free(luser);
1298 						continue;
1299 					}
1300 				} else {
1301 					if (db) fprintf(stderr, "AIX luser compare: problem=1\n");
1302 					problem = 1;
1303 				}
1304 				free(luser);
1305 			} else
1306 #endif
1307 			{
1308 				problem = 1;
1309 			}
1310 		}
1311 
1312 		if (problem) {
1313 			if (db) {
1314 				fprintf(stderr, "\"Password:\" did not "
1315 				    "appear: '%s'" " n=%d\n", instr, n);
1316 				if (db > 3 && n == 1 && j < 32) {
1317 					continue;
1318 				}
1319 			}
1320 			alarm(0);
1321 			signal(SIGALRM, SIG_DFL);
1322 			kill_child(pid, fd);
1323 			return 0;
1324 		}
1325 	}
1326 
1327 	alarm(0);
1328 	signal(SIGALRM, SIG_DFL);
1329 	if (alarm_fired) {
1330 		kill_child(pid, fd);
1331 		return 0;
1332 	}
1333 
1334 	if (db) fprintf(stderr, "\nsending passwd: %s\n", db > 2 ? pass : "****");
1335 	usleep(100 * 1000);
1336 	if (slow_pw) {
1337 		unsigned int k;
1338 		for (k = 0; k < strlen(pass); k++) {
1339 			write(fd, pass+k, 1);
1340 			usleep(100 * 1000);
1341 		}
1342 	} else {
1343 		write(fd, pass, strlen(pass));
1344 	}
1345 
1346 	alarm_fired = 0;
1347 	signal(SIGALRM, close_alarm);
1348 	alarm(15);
1349 
1350 	/*
1351 	 * try to drain the output, hopefully never as much as 4096 (motd?)
1352 	 * if we don't drain we may block at waitpid.  If we close(fd), the
1353 	 * make cause child to die by signal.
1354 	 */
1355 	if (rbuf && *rbuf_size > 0) {
1356 		/* asked to return output of command */
1357 		drain_size = *rbuf_size;
1358 		rsize = 0;
1359 	}
1360 	if (db) fprintf(stderr, "\ndraining:\n");
1361 	for (i = 0; i< drain_size; i++) {
1362 		int n;
1363 
1364 		cbuf[0] = '\0';
1365 		cbuf[1] = '\0';
1366 
1367 		n = read(fd, cbuf, 1);
1368 		if (n < 0 && errno == EINTR) {
1369 			if (db) fprintf(stderr, "\nEINTR n=%d i=%d --", n, i);
1370 			i--;
1371 			if (i < 0) i = 0;
1372 			continue;
1373 		}
1374 
1375 		if (db) fprintf(stderr, "\nn=%d i=%d errno=%d %.6f  '%s'", n, i, errno, dnowx(), cbuf);
1376 
1377 		if (n <= 0) {
1378 			break;
1379 		}
1380 		if (rbuf && *rbuf_size > 0) {
1381 			rbuf[rsize++] = cbuf[0];
1382 		}
1383 	}
1384 	if (db && rbuf) fprintf(stderr, "\nrbuf: '%s'\n", rbuf);
1385 
1386 	if (rbuf && *rbuf_size > 0) {
1387 		char *s = rbuf;
1388 		char *p = strdup(pass);
1389 		int n, o = 0;
1390 
1391 		n = strlen(p);
1392 		if (p[n-1] == '\n') {
1393 			p[n-1] = '\0';
1394 		}
1395 		/*
1396 		 * usually is: Password: mypassword\r\n\r\n<output-of-command>
1397 		 * and output will have \n -> \r\n
1398 		 */
1399 		if (rbuf[0] == ' ') {
1400 			s++;
1401 			o++;
1402 		}
1403 		if (strstr(s, p) == s) {
1404 			s += strlen(p);
1405 			o += strlen(p);
1406 			for (n = 0; n < 4; n++) {
1407 				if (s[0] == '\r' || s[0] == '\n') {
1408 					s++;
1409 					o++;
1410 				}
1411 			}
1412 		}
1413 		if (o > 0) {
1414 			int i = 0;
1415 			rsize -= o;
1416 			while (o < drain_size) {
1417 				rbuf[i++] = rbuf[o++];
1418 			}
1419 		}
1420 		*rbuf_size = rsize;
1421 		strzero(p);
1422 		free(p);
1423 	}
1424 
1425 	if (db) fprintf(stderr, "\n--\n");
1426 
1427 	alarm(0);
1428 	signal(SIGALRM, SIG_DFL);
1429 	if (alarm_fired) {
1430 		kill_child(pid, fd);
1431 		return 0;
1432 	}
1433 
1434 	slave_fd = -1;
1435 
1436 	pidw = waitpid(pid, &status, 0);
1437 	close(fd);
1438 
1439 	if (pid != pidw) {
1440 		return 0;
1441 	}
1442 
1443 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1444 		return 1; /* this is the only return of success. */
1445 	} else {
1446 		return 0;
1447 	}
1448 #endif	/* UNIXPW_SU */
1449 }
1450 
1451 int unixpw_verify(char *user, char *pass) {
1452 	int ok = 0;
1453 	if (unixpw_cmd) {
1454 		if (cmd_verify(user, pass)) {
1455 			rfbLog("unixpw_verify: cmd_verify login for '%s'"
1456 			    " succeeded.\n", user);
1457 			fflush(stderr);
1458 			ok = 1;
1459 		} else {
1460 			rfbLog("unixpw_verify: cmd_verify login for '%s'"
1461 			    " failed.\n", user);
1462 			fflush(stderr);
1463 			usleep(3000*1000);
1464 			ok = 0;
1465 		}
1466 	} else if (unixpw_nis) {
1467 		if (crypt_verify(user, pass)) {
1468 			rfbLog("unixpw_verify: crypt_verify login for '%s'"
1469 			    " succeeded.\n", user);
1470 			fflush(stderr);
1471 			ok = 1;
1472 		} else {
1473 			rfbLog("unixpw_verify: crypt_verify login for '%s'"
1474 			    " failed.\n", user);
1475 			fflush(stderr);
1476 			usleep(3000*1000);
1477 			ok = 0;
1478 		}
1479 	} else {
1480 		if (su_verify(user, pass, NULL, NULL, NULL, 1)) {
1481 			rfbLog("unixpw_verify: su_verify login for '%s'"
1482 			    " succeeded.\n", user);
1483 			fflush(stderr);
1484 			ok = 1;
1485 		} else {
1486 			rfbLog("unixpw_verify: su_verify login for '%s'"
1487 			    " failed.\n", user);
1488 			fflush(stderr);
1489 			/* use su(1)'s sleep */
1490 			ok = 0;
1491 		}
1492 	}
1493 	return ok;
1494 }
1495 
1496 static int skip_it = 0;
1497 
1498 static void progress_skippy(void) {
1499 	int i, msec = get_net_latency();	/* probabaly not set yet.. */
1500 
1501 	if (msec > 300) {
1502 		msec = 300;
1503 	} else if (msec <= 100) {
1504 		msec = 100;
1505 	}
1506 
1507 	skip_it = 1;
1508 	for (i = 0; i < 5; i++) {
1509 		if (i == 2) {
1510 			rfbPE(msec * 1000);
1511 		} else {
1512 			rfbPE(-1);
1513 		}
1514 		usleep(10*1000);
1515 	}
1516 	skip_it = 0;
1517 
1518 	usleep(50*1000);
1519 }
1520 
1521 void check_unixpw_userprefs(void) {
1522 	char *prefs = getenv("FD_USERPREFS");
1523 	if (keep_unixpw_user == NULL || keep_unixpw_opts == NULL) {
1524 		return;
1525 	}
1526 #if LIBVNCSERVER_HAVE_PWD_H
1527 	if (prefs != NULL && !strchr(prefs, '/')) {
1528 		struct passwd *pw = getpwnam(keep_unixpw_user);
1529 		if (pw != NULL) {
1530 			char *file;
1531 			FILE *f;
1532 
1533 			file = (char *) malloc(strlen(pw->pw_dir) + 1 + strlen(prefs) + 1);
1534 			sprintf(file, "%s/%s", pw->pw_dir, prefs);
1535 
1536 			f = fopen(file, "r");
1537 			if (f) {
1538 				char *t, *q, buf[1024];
1539 				memset(buf, 0, sizeof(buf));
1540 
1541 				fgets(buf, 1024, f);
1542 				fclose(f);
1543 
1544 				q = strchr(buf, '\n');
1545 				if (q) *q = '\0';
1546 				q = strchr(buf, '\r');
1547 				if (q) *q = '\0';
1548 
1549 				rfbLog("read user prefs %s: %s\n", file, buf);
1550 
1551 				if (buf[0] == '#') buf[0] = '\0';
1552 
1553 				t = (char *) malloc(strlen(keep_unixpw_opts) + 1 + strlen(buf) + 1);
1554 				sprintf(t, "%s,%s", keep_unixpw_opts, buf);
1555 				free(keep_unixpw_opts);
1556 				keep_unixpw_opts = t;
1557 			} else {
1558 				rfbLog("could not read user prefs %s\n", file);
1559 				rfbLogPerror("fopen");
1560 			}
1561 			free(file);
1562 		}
1563 	}
1564 #endif
1565 }
1566 
1567 
1568 void unixpw_verify_screen(char *user, char *pass) {
1569 	int x, y;
1570 	char li[] = "Login incorrect";
1571 	char ls[] = "Login succeeded";
1572 	char log[] = "login: ";
1573 	char *colon = NULL;
1574 	ClientData *cd = NULL;
1575 	int ok;
1576 
1577 if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********");
1578 	rfbLog("unixpw_verify: '%s'\n", user ? user : "(null)");
1579 
1580 	if (user) {
1581 		colon = strchr(user, ':');
1582 	}
1583 	if (colon) {
1584 		*colon = '\0';
1585 		rfbLog("unixpw_verify: colon: '%s'\n", user);
1586 	}
1587 	fflush(stderr);
1588 	if (unixpw_client) {
1589 		cd = (ClientData *) unixpw_client->clientData;
1590 		if (cd) {
1591 			char *str = (char *)malloc(strlen("UNIX:") +
1592 			    strlen(user) + 1);
1593 			sprintf(str, "UNIX:%s", user);
1594 			if (cd->username) {
1595 				free(cd->username);
1596 			}
1597 			cd->username = str;
1598 		}
1599 	}
1600 
1601 	ok = unixpw_verify(user, pass);
1602 
1603 	if (ok) {
1604 		char_row++;
1605 		char_col = 0;
1606 
1607 		x = text_x();
1608 		y = text_y();
1609 		rfbDrawString(pscreen, &default8x16Font, x, y, ls, white_pixel());
1610 		unixpw_mark();
1611 
1612 		progress_skippy();
1613 
1614 		unixpw_accept(user);
1615 
1616 		if (keep_unixpw) {
1617 			keep_unixpw_user = strdup(user);
1618 			keep_unixpw_pass = strdup(pass);
1619 			if (colon) {
1620 				keep_unixpw_opts = strdup(colon+1);
1621 			} else {
1622 				keep_unixpw_opts = strdup("");
1623 			}
1624 			check_unixpw_userprefs();
1625 		}
1626 
1627 		if (colon) *colon = ':';
1628 
1629 		return;
1630 	}
1631 	if (colon) *colon = ':';
1632 
1633 	if (tries < 2) {
1634 		char_row++;
1635 		char_col = 0;
1636 
1637 		x = text_x();
1638 		y = text_y();
1639 		rfbDrawString(pscreen, &default8x16Font, x, y, li, white_pixel());
1640 
1641 		char_row += 2;
1642 
1643 		x = text_x();
1644 		y = text_y();
1645 		rfbDrawString(pscreen, &default8x16Font, x, y, log, white_pixel());
1646 
1647 		char_col = strlen(log);
1648 
1649 		unixpw_mark();
1650 
1651 		unixpw_last_try_time = time(NULL);
1652 		unixpw_keystroke(0, 0, 2);
1653 		tries++;
1654 	} else {
1655 		unixpw_deny();
1656 	}
1657 }
1658 
1659 static void set_db(void) {
1660 	if (getenv("DEBUG_UNIXPW")) {
1661 		db = atoi(getenv("DEBUG_UNIXPW"));
1662 		rfbLog("DEBUG_UNIXPW: %d\n", db);
1663 	}
1664 }
1665 
1666 void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
1667 	int x, y, i, rc, nmax = 100;
1668 	static char user_r[100], user[100], pass[100];
1669 	static int  u_cnt = 0, p_cnt = 0, t_cnt = 0, first = 1;
1670 	static int echo = 1;
1671 	char keystr[100];
1672 	char *str;
1673 
1674 	if (skip_it) {
1675 		return;
1676 	}
1677 
1678 	if (first) {
1679 		set_db();
1680 		first = 0;
1681 		for (i=0; i < nmax; i++) {
1682 			user_r[i] = '\0';
1683 			user[i] = '\0';
1684 			pass[i] = '\0';
1685 		}
1686 	}
1687 
1688 	if (init) {
1689 		in_login = 1;
1690 		in_passwd = 0;
1691 		unixpw_denied = 0;
1692 		echo = 1;
1693 		if (init == 1) {
1694 			tries = 0;
1695 		}
1696 
1697 		u_cnt = 0;
1698 		p_cnt = 0;
1699 		t_cnt = 0;
1700 		for (i=0; i<nmax; i++) {
1701 			user[i] = '\0';
1702 			pass[i] = '\0';
1703 		}
1704 		if (keep_unixpw_user) {
1705 			free(keep_unixpw_user);
1706 			keep_unixpw_user = NULL;
1707 		}
1708 		if (keep_unixpw_pass) {
1709 			strzero(keep_unixpw_pass);
1710 			free(keep_unixpw_pass);
1711 			keep_unixpw_pass = NULL;
1712 		}
1713 		if (keep_unixpw_opts) {
1714 			strzero(keep_unixpw_opts);
1715 			free(keep_unixpw_opts);
1716 			keep_unixpw_opts = NULL;
1717 		}
1718 
1719 		return;
1720 	}
1721 
1722 	if (unixpw_denied) {
1723 		rfbLog("unixpw_keystroke: unixpw_denied state: 0x%x\n", (int) keysym);
1724 		return;
1725 	}
1726 	if (keysym <= 0) {
1727 		rfbLog("unixpw_keystroke: bad keysym1: 0x%x\n", (int) keysym);
1728 		return;
1729 	}
1730 
1731 	/* rfbKeySym = uint32_t */
1732 	/* KeySym = XID = CARD32 = (unsigned long or unsigned int on LONG64) */
1733 	X_LOCK;
1734 	str = XKeysymToString(keysym);
1735 	X_UNLOCK;
1736 	if (str == NULL) {
1737 		rfbLog("unixpw_keystroke: bad keysym2: 0x%x\n", (int) keysym);
1738 		return;
1739 	}
1740 
1741 	rc = snprintf(keystr, 100, "%s", str);
1742 	if (rc < 1 || rc > 90) {
1743 		rfbLog("unixpw_keystroke: bad keysym3: 0x%x\n", (int) keysym);
1744 		return;
1745 	}
1746 
1747 	if (db > 2) {
1748 		fprintf(stderr, "%s / %s  0x%x %s\n", in_login ? "login":"pass ",
1749 		    down ? "down":"up  ", keysym, keystr);
1750 	}
1751 
1752 	if (keysym == XK_Return || keysym == XK_Linefeed || keysym == XK_Tab) {
1753 		/* let "up" pass down below for Return case */
1754 		if (down) {
1755 			return;
1756 		}
1757 	} else if (! down) {
1758 		return;
1759 	}
1760 	if (keysym == XK_F1) {
1761 		char h1[] = "F1-Help:  For 'login:' type in the username and press Enter, then for 'Password:' enter the password.";
1762 		char hf[] = "  Once logged in, username's X session will be searched for and if found then attached to.";
1763 		char hc[] = "  Once logged in, username's X session is sought and attached to, otherwise a new session is created.";
1764 		char hx[] = "  Once logged in, username's X session is sought and attached to, otherwise a login greeter is presented.";
1765 		char h2[] = "  Specify options after a ':' like this:  username:opt,opt=val,...    Where an opt may be any of:";
1766 		char h3[] = "    scale=... (n/m); scale_cursor=... (sc=); solid (so); id=; repeat; clear_mods (cm); clear_keys (ck);";
1767 		char h4[] = "    clear_all (ca); speeds=... (sp=); readtimeout=... (rd=) rotate=... (ro=); noncache (nc) (nc=n);";
1768 		char h5[] = "    geom=WxHxD (ge=); nodisplay=... (nd=); viewonly (vo); tag=...; gnome kde twm fvwm mwm dtwm wmaker";
1769 		char h6[] = "    xfce lxde enlightenment Xsession failsafe.   Examples:  fred:3/4,so,cm  wilma:geom=1024x768x16,kde";
1770 		int ch = 13, p;
1771 		if (!pscreen || pscreen->width < 640 || pscreen->height < 480) {
1772 			return;
1773 		}
1774 		if (f1_help) {
1775 			p = black_pixel();
1776 			f1_help = 0;
1777 		} else {
1778 			p = white_pixel();
1779 			f1_help = 1;
1780 			unixpw_last_try_time = time(NULL) + 45;
1781 		}
1782 		rfbDrawString(pscreen, &default6x13Font, 8, 2+1*ch, h1, p);
1783 		if (use_dpy == NULL) {
1784 			;
1785 		} else if (strstr(use_dpy, "cmd=FINDDISPLAY")) {
1786 			rfbDrawString(pscreen, &default6x13Font, 8, 2+2*ch, hf, p);
1787 		} else if (strstr(use_dpy, "cmd=FINDCREATEDISPLAY")) {
1788 			if (strstr(use_dpy, "xdmcp")) {
1789 				rfbDrawString(pscreen, &default6x13Font, 8, 2+2*ch, hx, p);
1790 			} else {
1791 				rfbDrawString(pscreen, &default6x13Font, 8, 2+2*ch, hc, p);
1792 			}
1793 		}
1794 		rfbDrawString(pscreen, &default6x13Font, 8, 2+3*ch, h2, p);
1795 		rfbDrawString(pscreen, &default6x13Font, 8, 2+4*ch, h3, p);
1796 		rfbDrawString(pscreen, &default6x13Font, 8, 2+5*ch, h4, p);
1797 		rfbDrawString(pscreen, &default6x13Font, 8, 2+6*ch, h5, p);
1798 		rfbDrawString(pscreen, &default6x13Font, 8, 2+7*ch, h6, p);
1799 		if (!f1_help) {
1800 			rfbDrawString(pscreen, &default6x13Font, 8, 2+1*ch, "F1-Help:", white_pixel());
1801 		}
1802 		unixpw_mark();
1803 		return;
1804 	}
1805 	if (unixpw_system_greeter_active && keysym == XK_Escape) {
1806 		char *u = get_user_name();
1807 		if (keep_unixpw) {
1808 			char *colon = strchr(user, ':');
1809 			keep_unixpw_user = strdup(u);
1810 			keep_unixpw_pass = strdup("");
1811 			if (colon) {
1812 				keep_unixpw_opts = strdup(colon+1);
1813 			} else {
1814 				keep_unixpw_opts = strdup("");
1815 			}
1816 			check_unixpw_userprefs();
1817 		}
1818 		unixpw_system_greeter_active = 2;
1819 		set_env("X11VNC_XDM_ONLY", "1");
1820 		rfbLog("unixpw_system_greeter: VNC client pressed 'Escape'. Allowing\n");
1821 		rfbLog("unixpw_system_greeter: a *FREE* (no password) connection to\n");
1822 		rfbLog("unixpw_system_greeter: the system XDM/GDM/KDM login greeter.\n");
1823 		if (1) {
1824 			char msg[] = " Please wait... ";
1825 			rfbDrawString(pscreen, &default8x16Font,
1826 			    text_x(), text_y(), msg, white_pixel());
1827 			unixpw_mark();
1828 
1829 			progress_skippy();
1830 		}
1831 		unixpw_accept(u);
1832 		free(u);
1833 		return;
1834 	}
1835 
1836 	if (in_login && keysym == XK_Escape && u_cnt == 0) {
1837 		echo = 0;
1838 		rfbLog("unixpw_keystroke: echo off.\n");
1839 		return;
1840 	}
1841 
1842 	t_cnt++;
1843 
1844 	if (in_login) {
1845 		if (keysym == XK_BackSpace || keysym == XK_Delete) {
1846 			if (u_cnt > 0) {
1847 				user[u_cnt-1] = '\0';
1848 				u_cnt--;
1849 
1850 				x = text_x();
1851 				y = text_y();
1852 				if (scaling) {
1853 					int x2 = x / scale_fac_x;
1854 					int y2 = y / scale_fac_y;
1855 					int w2 = char_w / scale_fac_x;
1856 					int h2 = char_h / scale_fac_y;
1857 
1858 					x2 = nfix(x2, dpy_x);
1859 					y2 = nfix(y2, dpy_y);
1860 
1861 					zero_fb(x2 - w2, y2 - h2, x2, y2);
1862 					mark_rect_as_modified(x2 - w2,
1863 					    y2 - h2, x2, y2, 0);
1864 				} else {
1865 					zero_fb(x - char_w, y - char_h, x, y);
1866 					mark_rect_as_modified(x - char_w,
1867 					    y - char_h, x, y, 0);
1868 				}
1869 				char_col--;
1870 			}
1871 
1872 			return;
1873 		}
1874 
1875 		if (keysym == XK_Return || keysym == XK_Linefeed || keysym == XK_Tab) {
1876 			char pw[] = "Password: ";
1877 
1878 			if (down) {
1879 				/*
1880 				 * require Up so the Return Up is not processed
1881 				 * by the normal session after login.
1882 				 * (actually we already returned above)
1883 				 */
1884 				return;
1885 			}
1886 
1887 			if (t_cnt == 1) {
1888 				/* accidental initial return, e.g. from xterm */
1889 				return;
1890 			}
1891 
1892 			in_login = 0;
1893 			in_passwd = 1;
1894 
1895 			char_row++;
1896 			char_col = 0;
1897 
1898 			x = text_x();
1899 			y = text_y();
1900 			rfbDrawString(pscreen, &default8x16Font, x, y, pw,
1901 			    white_pixel());
1902 
1903 			char_col = strlen(pw);
1904 			unixpw_mark();
1905 			return;
1906 		}
1907 
1908 		if (u_cnt == 0 && keysym == XK_Up) {
1909 			/*
1910 			 * Allow user to hit Up arrow at beginning to
1911 			 * regain their username plus any options.
1912 			 */
1913 			int i;
1914 			for (i=0; i < nmax; i++) {
1915 				user[i] = '\0';
1916 			}
1917 			for (i=0; i < nmax; i++) {
1918 				char str[10];
1919 				user[u_cnt++] = user_r[i];
1920 				if (user_r[i] == '\0') {
1921 					break;
1922 				}
1923 				str[0] = (char) user_r[i];
1924 				str[1] = '\0';
1925 
1926 				x = text_x();
1927 				y = text_y();
1928 				if (echo) {
1929 					rfbDrawString(pscreen, &default8x16Font, x, y,
1930 					    str, white_pixel());
1931 				}
1932 				mark_rect_as_modified(x, y-char_h, x+char_w,
1933 				    y, scaling);
1934 				char_col++;
1935 				usleep(10*1000);
1936 			}
1937 			return;
1938 		}
1939 
1940 		if (keysym < ' ' || keysym >= 0x7f) {
1941 			/* require normal keyboard characters for username */
1942 			rfbLog("unixpw_keystroke: bad keysym4: 0x%x\n", (int) keysym);
1943 			return;
1944 		}
1945 
1946 		if (u_cnt >= nmax - 1) {
1947 			/* user[u_cnt=99] will be '\0' */
1948 			rfbLog("unixpw_deny: username too long: %d\n", u_cnt);
1949 			for (i=0; i<nmax; i++) {
1950 				user[i] = '\0';
1951 				pass[i] = '\0';
1952 			}
1953 			unixpw_deny();
1954 			return;
1955 		}
1956 
1957 #if 0
1958 		user[u_cnt++] = keystr[0];
1959 #else
1960 		user[u_cnt++] = (char) keysym;
1961 		for (i=0; i < nmax; i++) {
1962 			/* keep a full copy of username */
1963 			user_r[i] = user[i];
1964 		}
1965 		keystr[0] = (char) keysym;
1966 #endif
1967 		keystr[1] = '\0';
1968 
1969 		x = text_x();
1970 		y = text_y();
1971 
1972 if (db && db <= 2) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x  '%s'\n", u_cnt, x, y, keysym, keystr);
1973 
1974 		if (echo ) {
1975 			rfbDrawString(pscreen, &default8x16Font, x, y, keystr, white_pixel());
1976 		}
1977 
1978 		mark_rect_as_modified(x, y-char_h, x+char_w, y, scaling);
1979 		char_col++;
1980 
1981 		return;
1982 
1983 	} else if (in_passwd) {
1984 		if (keysym == XK_BackSpace || keysym == XK_Delete) {
1985 			if (p_cnt > 0) {
1986 				pass[p_cnt-1] = '\0';
1987 				p_cnt--;
1988 			}
1989 			return;
1990 		}
1991 		if (keysym == XK_Return || keysym == XK_Linefeed) {
1992 			if (down) {
1993 				/*
1994 				 * require Up so the Return Up is not processed
1995 				 * by the normal session after login.
1996 				 * (actually we already returned above)
1997 				 */
1998 				return;
1999 			}
2000 
2001 			if (1) {
2002 				char msg[] = " Please wait... ";
2003 				rfbDrawString(pscreen, &default8x16Font,
2004 				    text_x(), text_y(), msg, white_pixel());
2005 				unixpw_mark();
2006 
2007 				progress_skippy();
2008 			}
2009 
2010 			in_login = 0;
2011 			in_passwd = 0;
2012 
2013 			pass[p_cnt++] = '\n';
2014 			unixpw_verify_screen(user, pass);
2015 			for (i=0; i<nmax; i++) {
2016 				user[i] = '\0';
2017 				pass[i] = '\0';
2018 			}
2019 			return;
2020 		}
2021 
2022 		if (keysym < ' ' || keysym >= 0x7f) {
2023 			/* require normal keyboard characters for password */
2024 			return;
2025 		}
2026 
2027 		if (p_cnt >= nmax - 2) {
2028 			/* pass[u_cnt=98] will be '\n' */
2029 			/* pass[u_cnt=99] will be '\0' */
2030 			rfbLog("unixpw_deny: password too long: %d\n", p_cnt);
2031 			for (i=0; i<nmax; i++) {
2032 				user[i] = '\0';
2033 				pass[i] = '\0';
2034 			}
2035 			unixpw_deny();
2036 			return;
2037 		}
2038 
2039 		pass[p_cnt++] = (char) keysym;
2040 
2041 		return;
2042 
2043 	} else {
2044 		/* should not happen... anyway clean up a bit. */
2045 		u_cnt = 0;
2046 		p_cnt = 0;
2047 		for (i=0; i<nmax; i++) {
2048 			user_r[i] = '\0';
2049 			user[i] = '\0';
2050 			pass[i] = '\0';
2051 		}
2052 
2053 		return;
2054 	}
2055 }
2056 
2057 static void apply_opts (char *user) {
2058 	char *p, *q, *str, *opts = NULL, *opts_star = NULL;
2059 	rfbClientPtr cl;
2060 	ClientData *cd;
2061 	int i, notmode = 0;
2062 
2063 	if (! unixpw_client) {
2064 		rfbLog("apply_opts: unixpw_client is NULL\n");
2065 		clean_up_exit(1);
2066 	}
2067 	cd = (ClientData *) unixpw_client->clientData;
2068 	cl = unixpw_client;
2069 
2070 	if (! cd) {
2071 		rfbLog("apply_opts: no ClientData\n");
2072 	}
2073 
2074 	if (user && cd) {
2075 		if (cd->unixname) {
2076 			free(cd->unixname);
2077 		}
2078 		cd->unixname = strdup(user);
2079 		rfbLog("apply_opts: set unixname to: %s\n", cd->unixname);
2080 	}
2081 
2082 	if (! unixpw_list) {
2083 		return;
2084 	}
2085 	str = strdup(unixpw_list);
2086 
2087 	/* apply any per-user options. */
2088 	if (str[0] == '!') {
2089 		p = strtok(str+1, ",");
2090 		notmode = 1;
2091 	} else {
2092 		p = strtok(str, ",");
2093 	}
2094 	while (p) {
2095 		if ( (q = strchr(p, ':')) != NULL ) {
2096 			*q = '\0';	/* get rid of options. */
2097 		} else {
2098 			p = strtok(NULL, ",");
2099 			continue;
2100 		}
2101 		if (user && !strcmp(user, p)) {
2102 			/* will not happen in notmode */
2103 			opts = strdup(q+1);
2104 		}
2105 		if (!strcmp("*", p)) {
2106 			opts_star = strdup(q+1);
2107 		}
2108 		p = strtok(NULL, ",");
2109 	}
2110 	free(str);
2111 
2112 	for (i=0; i < 2; i++) {
2113 		char *s = (i == 0) ? opts_star : opts;
2114 		if (s == NULL) {
2115 			continue;
2116 		}
2117 		p = strtok(s, "+");
2118 		while (p) {
2119 			if (!strcmp(p, "viewonly")) {
2120 				cl->viewOnly = TRUE;
2121 				if (cd) {
2122 					strncpy(cd->input, "-", CILEN);
2123 				}
2124 			} else if (!strcmp(p, "fullaccess")) {
2125 				cl->viewOnly = FALSE;
2126 				if (cd) {
2127 					strncpy(cd->input, "-", CILEN);
2128 				}
2129 			} else if ((q = strstr(p, "input=")) == p) {
2130 				q += strlen("input=");
2131 				if (cd) {
2132 					strncpy(cd->input, q, CILEN);
2133 				}
2134 			} else if (!strcmp(p, "deny")) {
2135 				cl->viewOnly = TRUE;
2136 				unixpw_deny();
2137 				break;
2138 			}
2139 			p = strtok(NULL, "+");
2140 		}
2141 		free(s);
2142 	}
2143 }
2144 
2145 void unixpw_accept(char *user) {
2146 	apply_opts(user);
2147 
2148 	if (!use_stunnel) {
2149 		ssl_helper_pid(0, -2);	/* waitall */
2150 	}
2151 
2152 	if (accept_cmd && strstr(accept_cmd, "popup") == accept_cmd) {
2153 		if (use_dpy && strstr(use_dpy, "WAIT:") == use_dpy &&
2154 		    dpy == NULL) {
2155 			/* handled in main() */
2156 			unixpw_client->onHold = TRUE;
2157 		} else if (! accept_client(unixpw_client)) {
2158 			unixpw_deny();
2159 			return;
2160 		}
2161 	}
2162 
2163 	if (started_as_root == 1 && users_list
2164 	    && strstr(users_list, "unixpw=") == users_list) {
2165 		if (getuid() && geteuid()) {
2166 			rfbLog("unixpw_accept: unixpw= but not root\n");
2167 			started_as_root = 2;
2168 		} else {
2169 			char *u = (char *)malloc(strlen(user)+1);
2170 
2171 			u[0] = '\0';
2172 			if (!strcmp(users_list, "unixpw=")) {
2173 				sprintf(u, "+%s", user);
2174 			} else {
2175 				char *p, *str = strdup(users_list);
2176 				p = strtok(str + strlen("unixpw="), ",");
2177 				while (p) {
2178 					if (!strcmp(p, user)) {
2179 						sprintf(u, "+%s", user);
2180 						break;
2181 					}
2182 					p = strtok(NULL, ",");
2183 				}
2184 				free(str);
2185 			}
2186 
2187 			if (u[0] == '\0') {
2188 				rfbLog("unixpw_accept skipping switch to user: %s\n", user);
2189 			} else if (switch_user(u, 0)) {
2190 				rfbLog("unixpw_accept switched to user: %s\n", user);
2191 			} else {
2192 				rfbLog("unixpw_accept failed to switch to user: %s\n", user);
2193 			}
2194 			free(u);
2195 		}
2196 	}
2197 
2198 	if (unixpw_login_viewonly) {
2199 		unixpw_client->viewOnly = TRUE;
2200 	}
2201 	unixpw_in_progress = 0;
2202 	/* mutex */
2203 	screen->permitFileTransfer = unixpw_file_xfer_save;
2204 	if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
2205 		/* this doesn't work: the current client is never registered! */
2206 #ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
2207 		rfbLog("rfbRegisterTightVNCFileTransferExtension: 1\n");
2208                 rfbRegisterTightVNCFileTransferExtension();
2209 #endif
2210 	}
2211 	unixpw_client = NULL;
2212 	mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
2213 	if (macosx_console) {
2214 		refresh_screen(1);
2215 	}
2216 }
2217 
2218 void unixpw_deny(void) {
2219 	int x, y, i;
2220 	char pd[] = "Permission denied.";
2221 
2222 	rfbLog("unixpw_deny: %d, %d\n", unixpw_denied, unixpw_in_progress);
2223 	if (! unixpw_denied) {
2224 		unixpw_denied = 1;
2225 
2226 		char_row += 2;
2227 		char_col = 0;
2228 		x = char_x + char_col * char_w;
2229 		y = char_y + char_row * char_h;
2230 
2231 		rfbDrawString(pscreen, &default8x16Font, x, y, pd, white_pixel());
2232 		unixpw_mark();
2233 
2234 		for (i=0; i<5; i++) {
2235 			rfbPE(-1);
2236 			rfbPE(-1);
2237 			usleep(500 * 1000);
2238 		}
2239 	}
2240 
2241 	if (unixpw_client) {
2242 		rfbCloseClient(unixpw_client);
2243 		rfbClientConnectionGone(unixpw_client);
2244 		rfbPE(-1);
2245 	}
2246 
2247 	unixpw_in_progress = 0;
2248 	/* mutex */
2249 	screen->permitFileTransfer = unixpw_file_xfer_save;
2250 	if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
2251 #ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
2252 		rfbLog("rfbRegisterTightVNCFileTransferExtension: 2\n");
2253                 rfbRegisterTightVNCFileTransferExtension();
2254 #endif
2255 	}
2256 	unixpw_client = NULL;
2257 	copy_screen();
2258 }
2259 
2260 void unixpw_msg(char *msg, int delay) {
2261 	int x, y, i;
2262 
2263 	char_row += 2;
2264 	char_col = 0;
2265 	x = char_x + char_col * char_w;
2266 	y = char_y + char_row * char_h;
2267 
2268 	rfbDrawString(pscreen, &default8x16Font, x, y, msg, white_pixel());
2269 	unixpw_mark();
2270 
2271 	for (i=0; i<5; i++) {
2272 		rfbPE(-1);
2273 		rfbPE(-1);
2274 		rfbPE(50 * 1000);
2275 		rfbPE(-1);
2276 		usleep(500 * 1000);
2277 		if (i >= delay) {
2278 			break;
2279 		}
2280 	}
2281 }
2282