2 * Copyright (c) 1995 - 2003 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. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 __RCSID("$Heimdal: kxd.c 20452 2007-04-19 20:04:19Z lha $"
39 static pid_t wait_on_pid
= -1;
43 * Signal handler that justs waits for the children when they die.
47 childhandler (int sig
)
53 pid
= waitpid (-1, &status
, WNOHANG
|WUNTRACED
);
54 if (pid
> 0 && pid
== wait_on_pid
)
57 signal (SIGCHLD
, childhandler
);
62 * Print the error message `format' and `...' on fd and die.
66 fatal (kx_context
*kc
, int fd
, char *format
, ...)
73 va_start(args
, format
);
76 vsnprintf ((char *)p
+ 4, sizeof(msg
) - 5, format
, args
);
77 syslog (LOG_ERR
, "%s", (char *)p
+ 4);
78 len
= strlen ((char *)p
+ 4);
79 p
+= kx_put_int (len
, p
, 4, 4);
81 kx_write (kc
, fd
, msg
, p
- msg
);
87 * Remove all sockets and cookie files.
91 cleanup(int nsockets
, struct x_socket
*sockets
)
97 for (i
= 0; i
< nsockets
; ++i
) {
98 if (sockets
[i
].pathname
!= NULL
) {
99 unlink (sockets
[i
].pathname
);
100 free (sockets
[i
].pathname
);
106 * Prepare to receive a connection on `sock'.
110 recv_conn (int sock
, kx_context
*kc
,
111 int *dispnr
, int *nsockets
, struct x_socket
**sockets
,
114 u_char msg
[1024], *p
;
117 struct passwd
*passwd
;
118 char remotehost
[MaxHostNameLen
];
119 char remoteaddr
[INET6_ADDRSTRLEN
];
125 memset(kc
, 0, sizeof(*kc
));
130 addrlen
= sizeof(kc
->__ss_this
);
131 kc
->thisaddr
= (struct sockaddr
*)&kc
->__ss_this
;
132 if (getsockname (sock
, kc
->thisaddr
, &addrlen
) < 0) {
133 syslog (LOG_ERR
, "getsockname: %m");
136 kc
->thisaddr_len
= addrlen
;
137 addrlen
= sizeof(kc
->__ss_that
);
138 kc
->thataddr
= (struct sockaddr
*)&kc
->__ss_that
;
139 if (getpeername (sock
, kc
->thataddr
, &addrlen
) < 0) {
140 syslog (LOG_ERR
, "getpeername: %m");
143 kc
->thataddr_len
= addrlen
;
145 getnameinfo_verified (kc
->thataddr
,
147 remotehost
, sizeof(remotehost
),
150 if (net_read (sock
, msg
, 4) != 4) {
151 syslog (LOG_ERR
, "read: %m");
156 if (ret
&& recv_v5_auth (kc
, sock
, msg
) == 0)
160 if (ret
&& recv_v4_auth (kc
, sock
, msg
) == 0)
164 syslog (LOG_ERR
, "unrecognized auth protocol: %x %x %x %x",
165 msg
[0], msg
[1], msg
[2], msg
[3]);
169 len
= kx_read (kc
, sock
, msg
, sizeof(msg
));
171 syslog (LOG_ERR
, "kx_read failed");
176 fatal(kc
, sock
, "Bad message");
178 p
+= kx_get_int (p
, &tmp32
, 4, 0);
179 len
= min(sizeof(user
), tmp32
);
180 memcpy (user
, p
, len
);
184 passwd
= k_getpwnam (user
);
186 fatal (kc
, sock
, "cannot find uid for %s", user
);
188 if (context_userok (kc
, user
) != 0)
189 fatal (kc
, sock
, "%s not allowed to login as %s",
194 if (flags
& PASSIVE
) {
198 tmp
= get_xsockets (nsockets
, sockets
, tcp_flag
);
200 fatal (kc
, sock
, "Cannot create X socket(s): %s",
205 if (chown_xsockets (*nsockets
, *sockets
,
206 passwd
->pw_uid
, passwd
->pw_gid
)) {
207 cleanup (*nsockets
, *sockets
);
208 fatal (kc
, sock
, "Cannot chown sockets: %s",
214 cleanup (*nsockets
, *sockets
);
215 fatal (kc
, sock
, "fork: %s", strerror(errno
));
216 } else if (pid
!= 0) {
220 cleanup (*nsockets
, *sockets
);
225 if (setgid (passwd
->pw_gid
) ||
226 initgroups(passwd
->pw_name
, passwd
->pw_gid
) ||
227 #ifdef HAVE_GETUDBNAM /* XXX this happens on crays */
228 setjob(passwd
->pw_uid
, 0) == -1 ||
230 setuid(passwd
->pw_uid
)) {
231 syslog(LOG_ERR
, "setting uid/groups: %m");
232 fatal (kc
, sock
, "cannot set uid");
235 ret
= getnameinfo(kc
->thataddr
, kc
->thataddr_len
,
236 remoteaddr
, sizeof(remoteaddr
),
237 NULL
, 0, NI_NUMERICHOST
);
239 fatal (kc
, sock
, "getnameinfo failed: %s", gai_strerror(ret
));
241 syslog (LOG_INFO
, "from %s(%s): %s -> %s",
242 remotehost
, remoteaddr
,
245 if (!(flags
& PASSIVE
)) {
246 p
+= kx_get_int (p
, &tmp32
, 4, 0);
247 len
= min(tmp32
, display_size
);
248 memcpy (display
, p
, len
);
251 p
+= kx_get_int (p
, &tmp32
, 4, 0);
252 len
= min(tmp32
, xauthfile_size
);
253 memcpy (xauthfile
, p
, len
);
254 xauthfile
[len
] = '\0';
257 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
258 if (flags
& KEEP_ALIVE
) {
261 setsockopt (sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&one
,
273 passive_session (kx_context
*kc
, int fd
, int sock
, int cookiesp
)
275 if (verify_and_remove_cookies (fd
, sock
, cookiesp
))
278 return copy_encrypted (kc
, fd
, sock
);
286 active_session (kx_context
*kc
, int fd
, int sock
, int cookiesp
)
288 fd
= connect_local_xsocket(0);
290 if (replace_cookie (fd
, sock
, xauthfile
, cookiesp
))
293 return copy_encrypted (kc
, fd
, sock
);
297 * Handle a new connection.
301 doit_conn (kx_context
*kc
,
302 int fd
, int meta_sock
, int flags
, int cookiesp
)
304 int sock
, sock2
, port
;
305 struct sockaddr_storage __ss_addr
;
306 struct sockaddr
*addr
= (struct sockaddr
*)&__ss_addr
;
307 struct sockaddr_storage __ss_thisaddr
;
308 struct sockaddr
*thisaddr
= (struct sockaddr
*)&__ss_thisaddr
;
310 u_char msg
[1024], *p
;
312 sock
= socket (kc
->thisaddr
->sa_family
, SOCK_STREAM
, 0);
314 syslog (LOG_ERR
, "socket: %m");
317 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
320 setsockopt (sock
, IPPROTO_TCP
, TCP_NODELAY
, (void *)&one
, sizeof(one
));
323 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
324 if (flags
& KEEP_ALIVE
) {
327 setsockopt (sock
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&one
,
331 memset (&__ss_addr
, 0, sizeof(__ss_addr
));
332 addr
->sa_family
= kc
->thisaddr
->sa_family
;
333 if (kc
->thisaddr_len
> sizeof(__ss_addr
)) {
334 syslog(LOG_ERR
, "error in af");
337 if (bind (sock
, addr
, kc
->thisaddr_len
) < 0) {
338 syslog (LOG_ERR
, "bind: %m");
341 addrlen
= sizeof(__ss_addr
);
342 if (getsockname (sock
, addr
, &addrlen
) < 0) {
343 syslog (LOG_ERR
, "getsockname: %m");
346 if (listen (sock
, SOMAXCONN
) < 0) {
347 syslog (LOG_ERR
, "listen: %m");
350 port
= socket_get_port(addr
);
354 p
+= kx_put_int (ntohs(port
), p
, 4, 4);
356 if (kx_write (kc
, meta_sock
, msg
, p
- msg
) < 0) {
357 syslog (LOG_ERR
, "write: %m");
361 addrlen
= sizeof(__ss_thisaddr
);
362 sock2
= accept (sock
, thisaddr
, &addrlen
);
364 syslog (LOG_ERR
, "accept: %m");
371 return passive_session (kc
, fd
, sock2
, cookiesp
);
373 return active_session (kc
, fd
, sock2
, cookiesp
);
377 * Is the current user the owner of the console?
381 check_user_console (kx_context
*kc
, int fd
)
385 if (stat ("/dev/console", &sb
) < 0)
386 fatal (kc
, fd
, "Cannot stat /dev/console: %s", strerror(errno
));
387 if (getuid() != sb
.st_uid
)
388 fatal (kc
, fd
, "Permission denied");
391 /* close down the new connection with a reasonable error message */
393 close_connection(int fd
, const char *message
)
395 char buf
[264]; /* max message */
400 mlen
= strlen(message
);
404 /* read first part of connection packet, to get byte order */
405 if(read(fd
, buf
, 6) != 6) {
412 *p
++ = 0; /* failed */
413 *p
++ = mlen
; /* length of message */
414 p
+= 4; /* skip protocol version */
415 p
+= 2; /* skip additional length */
416 memcpy(p
, message
, mlen
); /* copy message */
418 while((p
- buf
) % 4) /* pad to multiple of 4 bytes */
421 /* now fill in length of additional data */
423 buf
[6] = (p
- buf
- 8) / 4;
427 buf
[7] = (p
- buf
- 8) / 4;
429 write(fd
, buf
, p
- buf
);
435 * Handle a passive session on `sock'
439 doit_passive (kx_context
*kc
,
444 struct x_socket
*sockets
,
450 u_char msg
[1024], *p
;
453 display_num
= dispnr
;
455 snprintf (display
, display_size
, "localhost:%u", display_num
);
457 snprintf (display
, display_size
, ":%u", display_num
);
458 error
= create_and_write_cookie (xauthfile
, xauthfile_size
,
461 cleanup(nsockets
, sockets
);
462 fatal (kc
, sock
, "Cookie-creation failed: %s", strerror(error
));
471 len
= strlen (display
);
472 tmp
= kx_put_int (len
, p
, rem
, 4);
473 if (tmp
< 0 || rem
< len
+ 4) {
474 syslog (LOG_ERR
, "doit: buffer too small");
475 cleanup(nsockets
, sockets
);
481 memcpy (p
, display
, len
);
485 len
= strlen (xauthfile
);
486 tmp
= kx_put_int (len
, p
, rem
, 4);
487 if (tmp
< 0 || rem
< len
+ 4) {
488 syslog (LOG_ERR
, "doit: buffer too small");
489 cleanup(nsockets
, sockets
);
495 memcpy (p
, xauthfile
, len
);
499 if(kx_write (kc
, sock
, msg
, p
- msg
) < 0) {
500 syslog (LOG_ERR
, "write: %m");
501 cleanup(nsockets
, sockets
);
513 if (sock
>= FD_SETSIZE
) {
514 syslog (LOG_ERR
, "fd too large");
515 cleanup(nsockets
, sockets
);
520 for (i
= 0; i
< nsockets
; ++i
) {
521 if (sockets
[i
].fd
>= FD_SETSIZE
) {
522 syslog (LOG_ERR
, "fd too large");
523 cleanup(nsockets
, sockets
);
526 FD_SET(sockets
[i
].fd
, &fds
);
528 ret
= select(FD_SETSIZE
, &fds
, NULL
, NULL
, NULL
);
531 if(FD_ISSET(sock
, &fds
)){
532 /* there are no processes left on the remote side
534 cleanup(nsockets
, sockets
);
537 for (i
= 0; i
< nsockets
; ++i
) {
538 if (FD_ISSET(sockets
[i
].fd
, &fds
)) {
539 if (sockets
[i
].flags
== TCP
) {
540 struct sockaddr_storage __ss_peer
;
541 struct sockaddr
*peer
= (struct sockaddr
*)&__ss_peer
;
542 socklen_t slen
= sizeof(__ss_peer
);
544 fd
= accept (sockets
[i
].fd
,
547 if (fd
< 0 && errno
!= EINTR
)
548 syslog (LOG_ERR
, "accept: %m");
551 if (fd
>= 0 && suspicious_address (fd
, peer
)) {
556 } else if(sockets
[i
].flags
== UNIX_SOCKET
) {
559 fd
= accept (sockets
[i
].fd
, NULL
, &zero
);
561 if (fd
< 0 && errno
!= EINTR
)
562 syslog (LOG_ERR
, "accept: %m");
563 #ifdef MAY_HAVE_X11_PIPES
564 } else if(sockets
[i
].flags
== STREAM_PIPE
) {
566 * this code tries to handle the
567 * send fd-over-pipe stuff for
571 struct strrecvfd strrecvfd
;
573 ret
= ioctl (sockets
[i
].fd
,
574 I_RECVFD
, &strrecvfd
);
575 if (ret
< 0 && errno
!= EINTR
) {
576 syslog (LOG_ERR
, "ioctl I_RECVFD: %m");
581 if (strrecvfd
.uid
!= getuid()) {
582 close (strrecvfd
.fd
);
590 #endif /* MAY_HAVE_X11_PIPES */
606 syslog (LOG_ERR
, "fork: %m");
609 close_connection(fd
, strerror(errno
));
610 } else if (child
== 0) {
611 for (i
= 0; i
< nsockets
; ++i
)
612 close (sockets
[i
].fd
);
613 return doit_conn (kc
, fd
, sock
, flags
, cookiesp
);
621 * Handle an active session on `sock'
625 doit_active (kx_context
*kc
,
630 u_char msg
[1024], *p
;
632 check_user_console (kc
, sock
);
637 if(kx_write (kc
, sock
, msg
, p
- msg
) < 0) {
638 syslog (LOG_ERR
, "write: %m");
645 len
= kx_read (kc
, sock
, msg
, sizeof(msg
));
647 syslog (LOG_ERR
, "read: %m");
651 if (*p
!= NEW_CONN
) {
652 syslog (LOG_ERR
, "bad_message: %d", *p
);
658 syslog (LOG_ERR
, "fork: %m");
661 } else if (child
== 0) {
662 return doit_conn (kc
, sock
, sock
, flags
, 1);
669 * Receive a connection on `sock' and process it.
673 doit(int sock
, int tcp_flag
)
679 struct x_socket
*sockets
;
682 flags
= recv_conn (sock
, &context
, &dispnr
, &nsockets
, &sockets
, tcp_flag
);
684 if (flags
& PASSIVE
) {
685 ret
= doit_passive (&context
, sock
, flags
, dispnr
,
686 nsockets
, sockets
, tcp_flag
);
688 ret
= doit_active (&context
, sock
, flags
, tcp_flag
);
689 cleanup(nsockets
, sockets
);
691 context_destroy (&context
);
695 static char *port_str
= NULL
;
696 static int inetd_flag
= 1;
697 static int tcp_flag
= 0;
698 static int version_flag
= 0;
699 static int help_flag
= 0;
701 struct getargs args
[] = {
702 { "inetd", 'i', arg_negative_flag
, &inetd_flag
,
703 "Not started from inetd" },
704 { "tcp", 't', arg_flag
, &tcp_flag
, "Use TCP" },
705 { "port", 'p', arg_string
, &port_str
, "Use this port",
707 { "version", 0, arg_flag
, &version_flag
},
708 { "help", 0, arg_flag
, &help_flag
}
714 arg_printusage (args
,
715 sizeof(args
) / sizeof(args
[0]),
722 * kxd - receive a forwarded X conncection
726 main (int argc
, char **argv
)
731 setprogname (argv
[0]);
732 roken_openlog ("kxd", LOG_ODELAY
| LOG_PID
, LOG_DAEMON
);
734 if (getarg (args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
,
742 print_version (NULL
);
747 struct servent
*s
= roken_getservbyname (port_str
, "tcp");
754 port
= strtol (port_str
, &ptr
, 10);
755 if (port
== 0 && ptr
== port_str
)
756 errx (1, "bad port `%s'", port_str
);
761 port
= krb5_getportbyname(NULL
, "kx", "tcp", KX_PORT
);
763 port
= k_getportbyname ("kx", "tcp", htons(KX_PORT
));
765 #error define KRB4 or KRB5
772 signal (SIGCHLD
, childhandler
);
773 return doit(STDIN_FILENO
, tcp_flag
);