2 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * Signal handler that justs waits for the children when they die.
48 childhandler (int sig
)
54 pid
= waitpid (-1, &status
, WNOHANG
|WUNTRACED
);
56 signal (SIGCHLD
, childhandler
);
61 fatal(int, des_cblock
*, des_key_schedule
,
62 struct sockaddr_in
*, struct sockaddr_in
*,
65 __attribute__ ((format (printf
, 6, 7)))
70 fatal (int fd
, des_cblock
*key
, des_key_schedule schedule
,
71 struct sockaddr_in
*thisaddr
,
72 struct sockaddr_in
*thataddr
,
80 va_start(args
, format
);
83 vsnprintf (p
+ 4, sizeof(msg
) - 5, format
, args
);
84 syslog (LOG_ERR
, p
+ 4);
86 p
+= krb_put_int (len
, p
, 4);
88 write_encrypted (fd
, msg
, p
- msg
, schedule
, key
, thisaddr
, thataddr
);
103 recv_conn (int sock
, des_cblock
*key
, des_key_schedule schedule
,
104 struct sockaddr_in
*thisaddr
,
105 struct sockaddr_in
*thataddr
)
110 char user
[ANAME_SZ
+ 1];
111 char instance
[INST_SZ
+ 1];
113 char version
[KRB_SENDAUTH_VLEN
+ 1];
114 struct passwd
*passwd
;
115 char remotehost
[MaxHostNameLen
];
118 u_char msg
[1024], *p
;
122 addrlen
= sizeof(*thisaddr
);
123 if (getsockname (sock
, (struct sockaddr
*)thisaddr
, &addrlen
) < 0 ||
124 addrlen
!= sizeof(*thisaddr
)) {
125 syslog (LOG_ERR
, "getsockname: %m");
128 addrlen
= sizeof(*thataddr
);
129 if (getpeername (sock
, (struct sockaddr
*)thataddr
, &addrlen
) < 0 ||
130 addrlen
!= sizeof(*thataddr
)) {
131 syslog (LOG_ERR
, "getpeername: %m");
135 inaddr2str (thataddr
->sin_addr
, remotehost
, sizeof(remotehost
));
137 k_getsockinst (sock
, instance
, sizeof(instance
));
138 status
= krb_recvauth (KOPT_DO_MUTUAL
, sock
, &ticket
, "rcmd", instance
,
139 thataddr
, thisaddr
, &auth
, "", schedule
,
141 if (status
!= KSUCCESS
) {
142 syslog (LOG_ERR
, "krb_recvauth: %s",
143 krb_get_err_text(status
));
146 if( strncmp(version
, KX_VERSION
, KRB_SENDAUTH_VLEN
) != 0) {
147 /* Try to be nice to old kx's */
148 if (strncmp (version
, KX_OLD_VERSION
, KRB_SENDAUTH_VLEN
) == 0) {
149 char *old_errmsg
= "\001Old version of kx. Please upgrade.";
151 syslog (LOG_ERR
, "Old version client (%s)", version
);
153 krb_net_read (sock
, user
, sizeof(user
));
154 krb_net_write (sock
, old_errmsg
, strlen(old_errmsg
) + 1);
158 fatal(sock
, key
, schedule
, thisaddr
, thataddr
,
159 "Bad version %s", version
);
161 memcpy(key
, &auth
.session
, sizeof(des_cblock
));
163 len
= read_encrypted (sock
, msg
, sizeof(msg
), &ret
,
164 schedule
, key
, thataddr
, thisaddr
);
169 fatal(sock
, key
, schedule
, thisaddr
, thataddr
,
172 p
+= krb_get_int (p
, &tmp
, 4, 0);
173 len
= min(sizeof(user
), tmp
);
174 strncpy (user
, p
, len
);
178 passwd
= k_getpwnam (user
);
180 fatal (sock
, key
, schedule
, thisaddr
, thataddr
,
182 if (kuserok(&auth
, user
) != 0)
183 fatal (sock
, key
, schedule
, thisaddr
, thataddr
,
184 "%s is not allowed to login as %s",
185 krb_unparse_name_long (auth
.pname
,
189 if (setgid (passwd
->pw_gid
) ||
190 initgroups(passwd
->pw_name
, passwd
->pw_gid
) ||
191 setuid(passwd
->pw_uid
)) {
192 fatal (sock
, key
, schedule
, thisaddr
, thataddr
,
195 syslog (LOG_INFO
, "from %s(%s): %s -> %s",
197 inet_ntoa(thataddr
->sin_addr
),
198 krb_unparse_name_long (auth
.pname
, auth
.pinst
, auth
.prealm
),
202 if (!(flags
& PASSIVE
)) {
203 p
+= krb_get_int (p
, &tmp
, 4, 0);
204 len
= min(tmp
, display_size
);
205 strncpy (display
, p
, len
);
208 p
+= krb_get_int (p
, &tmp
, 4, 0);
209 len
= min(tmp
, xauthfile_size
);
210 strncpy (xauthfile
, p
, len
);
213 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
214 if (flags
& KEEP_ALIVE
) {
217 setsockopt (sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&one
,
229 passive_session (int fd
, int sock
, des_cblock
*key
,
230 des_key_schedule schedule
)
232 if (verify_and_remove_cookies (fd
, sock
))
235 return copy_encrypted (fd
, sock
, key
, schedule
);
239 active_session (int fd
, int sock
, des_cblock
*key
,
240 des_key_schedule schedule
)
242 fd
= connect_local_xsocket(0);
244 if (replace_cookie (fd
, sock
, xauthfile
))
247 return copy_encrypted (fd
, sock
, key
, schedule
);
251 doit_conn (int fd
, int meta_sock
, int flags
,
252 des_cblock
*key
, des_key_schedule schedule
,
253 struct sockaddr_in
*thisaddr
,
254 struct sockaddr_in
*thataddr
)
257 struct sockaddr_in addr
;
259 u_char msg
[1024], *p
;
261 sock
= socket (AF_INET
, SOCK_STREAM
, 0);
263 syslog (LOG_ERR
, "socket: %m");
266 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
269 setsockopt (sock
, IPPROTO_TCP
, TCP_NODELAY
, (void *)&one
, sizeof(one
));
272 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
273 if (flags
& KEEP_ALIVE
) {
276 setsockopt (sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&one
,
280 memset (&addr
, 0, sizeof(addr
));
281 addr
.sin_family
= AF_INET
;
282 if (bind (sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
283 syslog (LOG_ERR
, "bind: %m");
286 addrlen
= sizeof(addr
);
287 if (getsockname (sock
, (struct sockaddr
*)&addr
,
289 syslog (LOG_ERR
, "getsockname: %m");
292 if (listen (sock
, SOMAXCONN
) < 0) {
293 syslog (LOG_ERR
, "listen: %m");
298 p
+= krb_put_int (ntohs(addr
.sin_port
), p
, 4);
300 if (write_encrypted (meta_sock
, msg
, p
- msg
, schedule
, key
,
301 thisaddr
, thataddr
) < 0) {
302 syslog (LOG_ERR
, "write: %m");
306 sock2
= accept (sock
, (struct sockaddr
*)thisaddr
, &addrlen
);
308 syslog (LOG_ERR
, "accept: %m");
315 return passive_session (fd
, sock2
, key
, schedule
);
317 return active_session (fd
, sock2
, key
, schedule
);
325 check_user_console (int fd
, des_cblock
*key
, des_key_schedule schedule
,
326 struct sockaddr_in
*thisaddr
,
327 struct sockaddr_in
*thataddr
)
331 if (stat ("/dev/console", &sb
) < 0)
332 fatal (fd
, key
, schedule
, thisaddr
, thataddr
,
333 "Cannot stat /dev/console");
334 if (getuid() != sb
.st_uid
)
335 fatal (fd
, key
, schedule
, thisaddr
, thataddr
,
336 "Permission denied");
340 * Receive a connection on `sock' and process it.
344 doit(int sock
, int tcpp
)
346 des_key_schedule schedule
;
349 struct sockaddr_in me
, him
;
351 u_char msg
[1024], *p
;
353 flags
= recv_conn (sock
, &key
, schedule
, &me
, &him
);
355 if (flags
& PASSIVE
) {
359 tmp
= get_xsockets (&localx
, tcpp
? &tcpx
: NULL
);
364 snprintf (display
, display_size
, "localhost:%u", display_num
);
366 snprintf (display
, display_size
, ":%u", display_num
);
367 if(create_and_write_cookie (xauthfile
, xauthfile_size
,
368 cookie
, cookie_len
)) {
369 syslog(LOG_ERR
, "create_and_write_cookie: %m");
370 fatal (sock
, &key
, schedule
, &me
, &him
,
371 "Cookie-creation failed with: %s",
379 len
= strlen (display
);
380 p
+= krb_put_int (len
, p
, 4);
381 strncpy (p
, display
, len
);
383 len
= strlen (xauthfile
);
384 p
+= krb_put_int (len
, p
, 4);
385 strncpy (p
, xauthfile
, len
);
388 if(write_encrypted (sock
, msg
, p
- msg
, schedule
, &key
,
390 syslog (LOG_ERR
, "write: %m");
401 FD_SET(localx
, &fds
);
405 if(select(FD_SETSIZE
, &fds
, NULL
, NULL
, NULL
) <=0)
407 if(FD_ISSET(sock
, &fds
)){
408 /* there are no processes left on the remote side
412 } else if(FD_ISSET(localx
, &fds
))
413 fd
= accept (localx
, NULL
, &zero
);
414 else if(tcpp
&& FD_ISSET(tcpx
, &fds
)) {
415 struct sockaddr_in peer
;
416 int len
= sizeof(peer
);
418 fd
= accept (tcpx
, (struct sockaddr
*)&peer
, &len
);
420 if (fd
>= 0 && suspicious_address (fd
, peer
)) {
430 syslog (LOG_ERR
, "accept: %m");
436 syslog (LOG_ERR
, "fork: %m");
438 } else if (child
== 0) {
442 return doit_conn (fd
, sock
, flags
,
443 &key
, schedule
, &me
, &him
);
449 check_user_console (sock
, &key
, schedule
, &me
, &him
);
454 if(write_encrypted (sock
, msg
, p
- msg
, schedule
, &key
,
456 syslog (LOG_ERR
, "write: %m");
464 len
= read_encrypted (sock
, msg
, sizeof(msg
), &ret
,
468 syslog (LOG_ERR
, "read: %m");
472 if (*p
!= NEW_CONN
) {
473 syslog (LOG_ERR
, "bad_message: %d", *p
);
479 syslog (LOG_ERR
, "fork: %m");
481 } else if (child
== 0) {
482 return doit_conn (localx
, sock
, flags
,
483 &key
, schedule
, &me
, &him
);
493 fprintf (stderr
, "Usage: %s [-i] [-t] [-p port]\n", __progname
);
498 * kxd - receive a forwarded X conncection
502 main (int argc
, char **argv
)
509 set_progname (argv
[0]);
511 while( (c
= getopt (argc
, argv
, "itp:")) != EOF
) {
520 port
= htons(atoi (optarg
));
529 mini_inetd (port
? port
: k_getportbyname("kx", "tcp",
531 openlog(__progname
, LOG_PID
|LOG_CONS
, LOG_DAEMON
);
532 signal (SIGCHLD
, childhandler
);
533 return doit(STDIN_FILENO
, tcpp
);