This commit was manufactured by cvs2svn to create tag
[heimdal.git] / appl / kx / kxd.c
blobea4eaf15f309e21d4fb7c259fd40900403ffe2a6
1 /*
2 * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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
31 * SUCH DAMAGE.
34 #include "kx.h"
36 RCSID("$Id$");
38 static pid_t wait_on_pid = -1;
39 static int done = 0;
42 * Signal handler that justs waits for the children when they die.
45 static RETSIGTYPE
46 childhandler (int sig)
48 pid_t pid;
49 int status;
51 do {
52 pid = waitpid (-1, &status, WNOHANG|WUNTRACED);
53 if (pid > 0 && pid == wait_on_pid)
54 done = 1;
55 } while(pid > 0);
56 signal (SIGCHLD, childhandler);
57 SIGRETURN(0);
61 * Print the error message `format' and `...' on fd and die.
64 void
65 fatal (kx_context *kc, int fd, char *format, ...)
67 u_char msg[1024];
68 u_char *p;
69 va_list args;
70 int len;
72 va_start(args, format);
73 p = msg;
74 *p++ = ERROR;
75 vsnprintf ((char *)p + 4, sizeof(msg) - 5, format, args);
76 syslog (LOG_ERR, "%s", (char *)p + 4);
77 len = strlen ((char *)p + 4);
78 p += KRB_PUT_INT (len, p, 4, 4);
79 p += len;
80 kx_write (kc, fd, msg, p - msg);
81 va_end(args);
82 exit (1);
86 * Remove all sockets and cookie files.
89 static void
90 cleanup(int nsockets, struct x_socket *sockets)
92 int i;
94 if(xauthfile[0])
95 unlink(xauthfile);
96 for (i = 0; i < nsockets; ++i) {
97 if (sockets[i].pathname != NULL) {
98 unlink (sockets[i].pathname);
99 free (sockets[i].pathname);
105 * Prepare to receive a connection on `sock'.
108 static int
109 recv_conn (int sock, kx_context *kc,
110 int *dispnr, int *nsockets, struct x_socket **sockets,
111 int tcp_flag)
113 u_char msg[1024], *p;
114 char user[256];
115 socklen_t addrlen;
116 struct passwd *passwd;
117 char remotehost[MaxHostNameLen];
118 char remoteaddr[INET6_ADDRSTRLEN];
119 int ret = 1;
120 int flags;
121 int len;
122 u_int32_t tmp32;
124 memset(kc, 0, sizeof(*kc));
125 *nsockets = 0;
126 *sockets = NULL;
127 *dispnr = 0;
129 addrlen = sizeof(kc->__ss_this);
130 kc->thisaddr = (struct sockaddr*)&kc->__ss_this;
131 if (getsockname (sock, kc->thisaddr, &addrlen) < 0) {
132 syslog (LOG_ERR, "getsockname: %m");
133 exit (1);
135 kc->thisaddr_len = addrlen;
136 addrlen = sizeof(kc->__ss_that);
137 kc->thataddr = (struct sockaddr*)&kc->__ss_that;
138 if (getpeername (sock, kc->thataddr, &addrlen) < 0) {
139 syslog (LOG_ERR, "getpeername: %m");
140 exit (1);
142 kc->thataddr_len = addrlen;
144 getnameinfo_verified (kc->thataddr,
145 kc->thataddr_len,
146 remotehost, sizeof(remotehost),
147 NULL, 0, 0);
149 if (net_read (sock, msg, 4) != 4) {
150 syslog (LOG_ERR, "read: %m");
151 exit (1);
154 #ifdef KRB5
155 if (ret && recv_v5_auth (kc, sock, msg) == 0)
156 ret = 0;
157 #endif
158 #ifdef KRB4
159 if (ret && recv_v4_auth (kc, sock, msg) == 0)
160 ret = 0;
161 #endif
162 if (ret) {
163 syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x",
164 msg[0], msg[1], msg[2], msg[3]);
165 exit (1);
168 len = kx_read (kc, sock, msg, sizeof(msg));
169 if (len < 0) {
170 syslog (LOG_ERR, "kx_read failed");
171 exit (1);
173 p = (u_char *)msg;
174 if (*p != INIT)
175 fatal(kc, sock, "Bad message");
176 p++;
177 p += krb_get_int (p, &tmp32, 4, 0);
178 len = min(sizeof(user), tmp32);
179 memcpy (user, p, len);
180 p += tmp32;
181 user[len] = '\0';
183 passwd = k_getpwnam (user);
184 if (passwd == NULL)
185 fatal (kc, sock, "cannot find uid for %s", user);
187 if (context_userok (kc, user) != 0)
188 fatal (kc, sock, "%s not allowed to login as %s",
189 kc->user, user);
191 flags = *p++;
193 if (flags & PASSIVE) {
194 pid_t pid;
195 int tmp;
197 tmp = get_xsockets (nsockets, sockets, tcp_flag);
198 if (tmp < 0) {
199 fatal (kc, sock, "Cannot create X socket(s): %s",
200 strerror(errno));
202 *dispnr = tmp;
204 if (chown_xsockets (*nsockets, *sockets,
205 passwd->pw_uid, passwd->pw_gid)) {
206 cleanup (*nsockets, *sockets);
207 fatal (kc, sock, "Cannot chown sockets: %s",
208 strerror(errno));
211 pid = fork();
212 if (pid == -1) {
213 cleanup (*nsockets, *sockets);
214 fatal (kc, sock, "fork: %s", strerror(errno));
215 } else if (pid != 0) {
216 wait_on_pid = pid;
217 while (!done)
218 pause ();
219 cleanup (*nsockets, *sockets);
220 exit (0);
224 if (setgid (passwd->pw_gid) ||
225 initgroups(passwd->pw_name, passwd->pw_gid) ||
226 #ifdef HAVE_GETUDBNAM /* XXX this happens on crays */
227 setjob(passwd->pw_uid, 0) == -1 ||
228 #endif
229 setuid(passwd->pw_uid)) {
230 syslog(LOG_ERR, "setting uid/groups: %m");
231 fatal (kc, sock, "cannot set uid");
234 ret = getnameinfo(kc->thataddr, kc->thataddr_len,
235 remoteaddr, sizeof(remoteaddr),
236 NULL, 0, NI_NUMERICHOST);
237 if (ret != 0)
238 fatal (kc, sock, "getnameinfo failed: %s", gai_strerror(ret));
240 syslog (LOG_INFO, "from %s(%s): %s -> %s",
241 remotehost, remoteaddr,
242 kc->user, user);
243 umask(077);
244 if (!(flags & PASSIVE)) {
245 p += krb_get_int (p, &tmp32, 4, 0);
246 len = min(tmp32, display_size);
247 memcpy (display, p, len);
248 display[len] = '\0';
249 p += tmp32;
250 p += krb_get_int (p, &tmp32, 4, 0);
251 len = min(tmp32, xauthfile_size);
252 memcpy (xauthfile, p, len);
253 xauthfile[len] = '\0';
254 p += tmp32;
256 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
257 if (flags & KEEP_ALIVE) {
258 int one = 1;
260 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
261 sizeof(one));
263 #endif
264 return flags;
271 static int
272 passive_session (kx_context *kc, int fd, int sock, int cookiesp)
274 if (verify_and_remove_cookies (fd, sock, cookiesp))
275 return 1;
276 else
277 return copy_encrypted (kc, fd, sock);
284 static int
285 active_session (kx_context *kc, int fd, int sock, int cookiesp)
287 fd = connect_local_xsocket(0);
289 if (replace_cookie (fd, sock, xauthfile, cookiesp))
290 return 1;
291 else
292 return copy_encrypted (kc, fd, sock);
296 * Handle a new connection.
299 static int
300 doit_conn (kx_context *kc,
301 int fd, int meta_sock, int flags, int cookiesp)
303 int sock, sock2, port;
304 struct sockaddr_storage __ss_addr;
305 struct sockaddr *addr = (struct sockaddr*)&__ss_addr;
306 struct sockaddr_storage __ss_thisaddr;
307 struct sockaddr *thisaddr = (struct sockaddr*)&__ss_thisaddr;
308 socklen_t addrlen;
309 u_char msg[1024], *p;
311 sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0);
312 if (sock < 0) {
313 syslog (LOG_ERR, "socket: %m");
314 return 1;
316 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
318 int one = 1;
319 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));
321 #endif
322 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
323 if (flags & KEEP_ALIVE) {
324 int one = 1;
326 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
327 sizeof(one));
329 #endif
330 memset (&__ss_addr, 0, sizeof(__ss_addr));
331 addr->sa_family = kc->thisaddr->sa_family;
332 if (kc->thisaddr_len > sizeof(__ss_addr)) {
333 syslog(LOG_ERR, "error in af");
334 return 1;
336 if (bind (sock, addr, kc->thisaddr_len) < 0) {
337 syslog (LOG_ERR, "bind: %m");
338 return 1;
340 addrlen = sizeof(__ss_addr);
341 if (getsockname (sock, addr, &addrlen) < 0) {
342 syslog (LOG_ERR, "getsockname: %m");
343 return 1;
345 if (listen (sock, SOMAXCONN) < 0) {
346 syslog (LOG_ERR, "listen: %m");
347 return 1;
349 port = socket_get_port(addr);
351 p = msg;
352 *p++ = NEW_CONN;
353 p += KRB_PUT_INT (ntohs(port), p, 4, 4);
355 if (kx_write (kc, meta_sock, msg, p - msg) < 0) {
356 syslog (LOG_ERR, "write: %m");
357 return 1;
360 addrlen = sizeof(__ss_thisaddr);
361 sock2 = accept (sock, thisaddr, &addrlen);
362 if (sock2 < 0) {
363 syslog (LOG_ERR, "accept: %m");
364 return 1;
366 close (sock);
367 close (meta_sock);
369 if (flags & PASSIVE)
370 return passive_session (kc, fd, sock2, cookiesp);
371 else
372 return active_session (kc, fd, sock2, cookiesp);
376 * Is the current user the owner of the console?
379 static void
380 check_user_console (kx_context *kc, int fd)
382 struct stat sb;
384 if (stat ("/dev/console", &sb) < 0)
385 fatal (kc, fd, "Cannot stat /dev/console: %s", strerror(errno));
386 if (getuid() != sb.st_uid)
387 fatal (kc, fd, "Permission denied");
390 /* close down the new connection with a reasonable error message */
391 static void
392 close_connection(int fd, const char *message)
394 char buf[264]; /* max message */
395 char *p;
396 int lsb = 0;
397 size_t mlen;
399 mlen = strlen(message);
400 if(mlen > 255)
401 mlen = 255;
403 /* read first part of connection packet, to get byte order */
404 if(read(fd, buf, 6) != 6) {
405 close(fd);
406 return;
408 if(buf[0] == 0x6c)
409 lsb++;
410 p = buf;
411 *p++ = 0; /* failed */
412 *p++ = mlen; /* length of message */
413 p += 4; /* skip protocol version */
414 p += 2; /* skip additional length */
415 memcpy(p, message, mlen); /* copy message */
416 p += mlen;
417 while((p - buf) % 4) /* pad to multiple of 4 bytes */
418 *p++ = 0;
420 /* now fill in length of additional data */
421 if(lsb) {
422 buf[6] = (p - buf - 8) / 4;
423 buf[7] = 0;
424 }else{
425 buf[6] = 0;
426 buf[7] = (p - buf - 8) / 4;
428 write(fd, buf, p - buf);
429 close(fd);
434 * Handle a passive session on `sock'
437 static int
438 doit_passive (kx_context *kc,
439 int sock,
440 int flags,
441 int dispnr,
442 int nsockets,
443 struct x_socket *sockets,
444 int tcp_flag)
446 int tmp;
447 int len;
448 size_t rem;
449 u_char msg[1024], *p;
450 int error;
452 display_num = dispnr;
453 if (tcp_flag)
454 snprintf (display, display_size, "localhost:%u", display_num);
455 else
456 snprintf (display, display_size, ":%u", display_num);
457 error = create_and_write_cookie (xauthfile, xauthfile_size,
458 cookie, cookie_len);
459 if (error) {
460 cleanup(nsockets, sockets);
461 fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
462 return 1;
465 p = msg;
466 rem = sizeof(msg);
467 *p++ = ACK;
468 --rem;
470 len = strlen (display);
471 tmp = KRB_PUT_INT (len, p, rem, 4);
472 if (tmp < 0 || rem < len + 4) {
473 syslog (LOG_ERR, "doit: buffer too small");
474 cleanup(nsockets, sockets);
475 return 1;
477 p += tmp;
478 rem -= tmp;
480 memcpy (p, display, len);
481 p += len;
482 rem -= len;
484 len = strlen (xauthfile);
485 tmp = KRB_PUT_INT (len, p, rem, 4);
486 if (tmp < 0 || rem < len + 4) {
487 syslog (LOG_ERR, "doit: buffer too small");
488 cleanup(nsockets, sockets);
489 return 1;
491 p += tmp;
492 rem -= tmp;
494 memcpy (p, xauthfile, len);
495 p += len;
496 rem -= len;
498 if(kx_write (kc, sock, msg, p - msg) < 0) {
499 syslog (LOG_ERR, "write: %m");
500 cleanup(nsockets, sockets);
501 return 1;
503 for (;;) {
504 pid_t child;
505 int fd = -1;
506 fd_set fds;
507 int i;
508 int ret;
509 int cookiesp = TRUE;
511 FD_ZERO(&fds);
512 if (sock >= FD_SETSIZE) {
513 syslog (LOG_ERR, "fd too large");
514 cleanup(nsockets, sockets);
515 return 1;
518 FD_SET(sock, &fds);
519 for (i = 0; i < nsockets; ++i) {
520 if (sockets[i].fd >= FD_SETSIZE) {
521 syslog (LOG_ERR, "fd too large");
522 cleanup(nsockets, sockets);
523 return 1;
525 FD_SET(sockets[i].fd, &fds);
527 ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
528 if(ret <= 0)
529 continue;
530 if(FD_ISSET(sock, &fds)){
531 /* there are no processes left on the remote side
533 cleanup(nsockets, sockets);
534 exit(0);
535 } else if(ret) {
536 for (i = 0; i < nsockets; ++i) {
537 if (FD_ISSET(sockets[i].fd, &fds)) {
538 if (sockets[i].flags == TCP) {
539 struct sockaddr_storage __ss_peer;
540 struct sockaddr *peer = (struct sockaddr*)&__ss_peer;
541 socklen_t len = sizeof(__ss_peer);
543 fd = accept (sockets[i].fd,
544 peer,
545 &len);
546 if (fd < 0 && errno != EINTR)
547 syslog (LOG_ERR, "accept: %m");
549 /* XXX */
550 if (fd >= 0 && suspicious_address (fd, peer)) {
551 close (fd);
552 fd = -1;
553 errno = EINTR;
555 } else if(sockets[i].flags == UNIX_SOCKET) {
556 socklen_t zero = 0;
558 fd = accept (sockets[i].fd, NULL, &zero);
560 if (fd < 0 && errno != EINTR)
561 syslog (LOG_ERR, "accept: %m");
562 #ifdef MAY_HAVE_X11_PIPES
563 } else if(sockets[i].flags == STREAM_PIPE) {
565 * this code tries to handle the
566 * send fd-over-pipe stuff for
567 * solaris
570 struct strrecvfd strrecvfd;
572 ret = ioctl (sockets[i].fd,
573 I_RECVFD, &strrecvfd);
574 if (ret < 0 && errno != EINTR) {
575 syslog (LOG_ERR, "ioctl I_RECVFD: %m");
578 /* XXX */
579 if (ret == 0) {
580 if (strrecvfd.uid != getuid()) {
581 close (strrecvfd.fd);
582 fd = -1;
583 errno = EINTR;
584 } else {
585 fd = strrecvfd.fd;
586 cookiesp = FALSE;
589 #endif /* MAY_HAVE_X11_PIPES */
590 } else
591 abort ();
592 break;
596 if (fd < 0) {
597 if (errno == EINTR)
598 continue;
599 else
600 return 1;
603 child = fork ();
604 if (child < 0) {
605 syslog (LOG_ERR, "fork: %m");
606 if(errno != EAGAIN)
607 return 1;
608 close_connection(fd, strerror(errno));
609 } else if (child == 0) {
610 for (i = 0; i < nsockets; ++i)
611 close (sockets[i].fd);
612 return doit_conn (kc, fd, sock, flags, cookiesp);
613 } else {
614 close (fd);
620 * Handle an active session on `sock'
623 static int
624 doit_active (kx_context *kc,
625 int sock,
626 int flags,
627 int tcp_flag)
629 u_char msg[1024], *p;
631 check_user_console (kc, sock);
633 p = msg;
634 *p++ = ACK;
636 if(kx_write (kc, sock, msg, p - msg) < 0) {
637 syslog (LOG_ERR, "write: %m");
638 return 1;
640 for (;;) {
641 pid_t child;
642 int len;
644 len = kx_read (kc, sock, msg, sizeof(msg));
645 if (len < 0) {
646 syslog (LOG_ERR, "read: %m");
647 return 1;
649 p = (u_char *)msg;
650 if (*p != NEW_CONN) {
651 syslog (LOG_ERR, "bad_message: %d", *p);
652 return 1;
655 child = fork ();
656 if (child < 0) {
657 syslog (LOG_ERR, "fork: %m");
658 if (errno != EAGAIN)
659 return 1;
660 } else if (child == 0) {
661 return doit_conn (kc, sock, sock, flags, 1);
662 } else {
668 * Receive a connection on `sock' and process it.
671 static int
672 doit(int sock, int tcp_flag)
674 int ret;
675 kx_context context;
676 int dispnr;
677 int nsockets;
678 struct x_socket *sockets;
679 int flags;
681 flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
683 if (flags & PASSIVE) {
684 ret = doit_passive (&context, sock, flags, dispnr,
685 nsockets, sockets, tcp_flag);
686 } else {
687 ret = doit_active (&context, sock, flags, tcp_flag);
688 cleanup(nsockets, sockets);
690 context_destroy (&context);
691 return ret;
694 static char *port_str = NULL;
695 static int inetd_flag = 1;
696 static int tcp_flag = 0;
697 static int version_flag = 0;
698 static int help_flag = 0;
700 struct getargs args[] = {
701 { "inetd", 'i', arg_negative_flag, &inetd_flag,
702 "Not started from inetd" },
703 { "tcp", 't', arg_flag, &tcp_flag, "Use TCP" },
704 { "port", 'p', arg_string, &port_str, "Use this port",
705 "port" },
706 { "version", 0, arg_flag, &version_flag },
707 { "help", 0, arg_flag, &help_flag }
710 static void
711 usage(int ret)
713 arg_printusage (args,
714 sizeof(args) / sizeof(args[0]),
715 NULL,
716 "host");
717 exit (ret);
721 * kxd - receive a forwarded X conncection
725 main (int argc, char **argv)
727 int port;
728 int optind = 0;
730 setprogname (argv[0]);
731 roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
733 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
734 &optind))
735 usage (1);
737 if (help_flag)
738 usage (0);
740 if (version_flag) {
741 print_version (NULL);
742 return 0;
745 if(port_str) {
746 struct servent *s = roken_getservbyname (port_str, "tcp");
748 if (s)
749 port = s->s_port;
750 else {
751 char *ptr;
753 port = strtol (port_str, &ptr, 10);
754 if (port == 0 && ptr == port_str)
755 errx (1, "bad port `%s'", port_str);
756 port = htons(port);
758 } else {
759 #if defined(KRB5)
760 port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT);
761 #elif defined(KRB4)
762 port = k_getportbyname ("kx", "tcp", htons(KX_PORT));
763 #else
764 #error define KRB4 or KRB5
765 #endif
768 if (!inetd_flag)
769 mini_inetd (port);
771 signal (SIGCHLD, childhandler);
772 return doit(STDIN_FILENO, tcp_flag);