add doxygen support and json export document support
[heimdal.git] / appl / kx / kxd.c
blob11f356f1cf070379dd6e81e9514565424a626f47
1 /*
2 * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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 += kx_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);
102 free(sockets);
106 * Prepare to receive a connection on `sock'.
109 static int
110 recv_conn (int sock, kx_context *kc,
111 int *dispnr, int *nsockets, struct x_socket **sockets,
112 int tcp_flag)
114 u_char msg[1024], *p;
115 char user[256];
116 socklen_t addrlen;
117 struct passwd *passwd;
118 char remotehost[MaxHostNameLen];
119 char remoteaddr[INET6_ADDRSTRLEN];
120 int ret = 1;
121 int flags;
122 int len;
123 uint32_t tmp32;
125 memset(kc, 0, sizeof(*kc));
126 *nsockets = 0;
127 *sockets = NULL;
128 *dispnr = 0;
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");
134 exit (1);
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");
141 exit (1);
143 kc->thataddr_len = addrlen;
145 getnameinfo_verified (kc->thataddr,
146 kc->thataddr_len,
147 remotehost, sizeof(remotehost),
148 NULL, 0, 0);
150 if (net_read (sock, msg, 4) != 4) {
151 syslog (LOG_ERR, "read: %m");
152 exit (1);
155 #ifdef KRB5
156 if (ret && recv_v5_auth (kc, sock, msg) == 0)
157 ret = 0;
158 #endif
159 if (ret) {
160 syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x",
161 msg[0], msg[1], msg[2], msg[3]);
162 exit (1);
165 len = kx_read (kc, sock, msg, sizeof(msg));
166 if (len < 0) {
167 syslog (LOG_ERR, "kx_read failed");
168 exit (1);
170 p = (u_char *)msg;
171 if (*p != INIT)
172 fatal(kc, sock, "Bad message");
173 p++;
174 if ((p - msg) < sizeof(msg))
175 fatal(kc, sock, "user");
177 p += kx_get_int (p, &tmp32, 4, 0);
178 if (tmp32 >= sizeof(user) - 1)
179 fatal(kc, sock, "user name too long");
180 if ((p - msg) + tmp32 >= sizeof(msg))
181 fatal(kc, sock, "user too long");
182 memcpy (user, p, tmp32);
183 p += tmp32;
184 user[tmp32] = '\0';
186 passwd = k_getpwnam (user);
187 if (passwd == NULL)
188 fatal (kc, sock, "cannot find uid for %s", user);
190 if (context_userok (kc, user) != 0)
191 fatal (kc, sock, "%s not allowed to login as %s",
192 kc->user, user);
194 if ((p - msg) >= sizeof(msg))
195 fatal(kc, sock, "user too long");
197 flags = *p++;
199 if (flags & PASSIVE) {
200 pid_t pid;
201 int tmp;
203 tmp = get_xsockets (nsockets, sockets, tcp_flag);
204 if (tmp < 0) {
205 fatal (kc, sock, "Cannot create X socket(s): %s",
206 strerror(errno));
208 *dispnr = tmp;
210 if (chown_xsockets (*nsockets, *sockets,
211 passwd->pw_uid, passwd->pw_gid)) {
212 cleanup (*nsockets, *sockets);
213 fatal (kc, sock, "Cannot chown sockets: %s",
214 strerror(errno));
217 pid = fork();
218 if (pid == -1) {
219 cleanup (*nsockets, *sockets);
220 fatal (kc, sock, "fork: %s", strerror(errno));
221 } else if (pid != 0) {
222 wait_on_pid = pid;
223 while (!done)
224 pause ();
225 cleanup (*nsockets, *sockets);
226 exit (0);
230 if (setgid (passwd->pw_gid) ||
231 initgroups(passwd->pw_name, passwd->pw_gid) ||
232 #ifdef HAVE_GETUDBNAM /* XXX this happens on crays */
233 setjob(passwd->pw_uid, 0) == -1 ||
234 #endif
235 setuid(passwd->pw_uid)) {
236 syslog(LOG_ERR, "setting uid/groups: %m");
237 fatal (kc, sock, "cannot set uid");
240 ret = getnameinfo(kc->thataddr, kc->thataddr_len,
241 remoteaddr, sizeof(remoteaddr),
242 NULL, 0, NI_NUMERICHOST);
243 if (ret != 0)
244 fatal (kc, sock, "getnameinfo failed: %s", gai_strerror(ret));
246 syslog (LOG_INFO, "from %s(%s): %s -> %s",
247 remotehost, remoteaddr,
248 kc->user, user);
249 umask(077);
250 if (!(flags & PASSIVE)) {
251 p += kx_get_int (p, &tmp32, 4, 0);
252 if (tmp32 > display_size)
253 fatal(kc, sock, "display too large");
254 if ((p - msg) + tmp32 + 8 >= sizeof(msg))
255 fatal(kc, sock, "user too long");
256 memcpy (display, p, tmp32);
257 display[tmp32] = '\0';
258 p += tmp32;
259 p += kx_get_int (p, &tmp32, 4, 0);
260 len = min(tmp32, xauthfile_size);
261 memcpy (xauthfile, p, len);
262 xauthfile[len] = '\0';
264 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
265 if (flags & KEEP_ALIVE) {
266 int one = 1;
268 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
269 sizeof(one));
271 #endif
272 return flags;
279 static int
280 passive_session (kx_context *kc, int fd, int sock, int cookiesp)
282 if (verify_and_remove_cookies (fd, sock, cookiesp))
283 return 1;
284 else
285 return copy_encrypted (kc, fd, sock);
292 static int
293 active_session (kx_context *kc, int fd, int sock, int cookiesp)
295 fd = connect_local_xsocket(0);
297 if (replace_cookie (fd, sock, xauthfile, cookiesp))
298 return 1;
299 else
300 return copy_encrypted (kc, fd, sock);
304 * Handle a new connection.
307 static int
308 doit_conn (kx_context *kc,
309 int fd, int meta_sock, int flags, int cookiesp)
311 int sock, sock2, port;
312 struct sockaddr_storage __ss_addr;
313 struct sockaddr *addr = (struct sockaddr*)&__ss_addr;
314 struct sockaddr_storage __ss_thisaddr;
315 struct sockaddr *thisaddr = (struct sockaddr*)&__ss_thisaddr;
316 socklen_t addrlen;
317 u_char msg[1024], *p;
319 sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0);
320 if (sock < 0) {
321 syslog (LOG_ERR, "socket: %m");
322 return 1;
324 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
326 int one = 1;
327 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));
329 #endif
330 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
331 if (flags & KEEP_ALIVE) {
332 int one = 1;
334 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
335 sizeof(one));
337 #endif
338 memset (&__ss_addr, 0, sizeof(__ss_addr));
339 __ss_addr.ss_family = kc->thisaddr->sa_family;
340 if (kc->thisaddr_len > sizeof(__ss_addr)) {
341 syslog(LOG_ERR, "error in af");
342 return 1;
344 if (bind (sock, addr, kc->thisaddr_len) < 0) {
345 syslog (LOG_ERR, "bind: %m");
346 return 1;
348 addrlen = sizeof(__ss_addr);
349 if (getsockname (sock, addr, &addrlen) < 0) {
350 syslog (LOG_ERR, "getsockname: %m");
351 return 1;
353 if (listen (sock, SOMAXCONN) < 0) {
354 syslog (LOG_ERR, "listen: %m");
355 return 1;
357 port = socket_get_port(addr);
359 p = msg;
360 *p++ = NEW_CONN;
361 p += kx_put_int (ntohs(port), p, 4, 4);
363 if (kx_write (kc, meta_sock, msg, p - msg) < 0) {
364 syslog (LOG_ERR, "write: %m");
365 return 1;
368 addrlen = sizeof(__ss_thisaddr);
369 sock2 = accept (sock, thisaddr, &addrlen);
370 if (sock2 < 0) {
371 syslog (LOG_ERR, "accept: %m");
372 return 1;
374 close (sock);
375 close (meta_sock);
377 if (flags & PASSIVE)
378 return passive_session (kc, fd, sock2, cookiesp);
379 else
380 return active_session (kc, fd, sock2, cookiesp);
384 * Is the current user the owner of the console?
387 static void
388 check_user_console (kx_context *kc, int fd)
390 struct stat sb;
392 if (stat ("/dev/console", &sb) < 0)
393 fatal (kc, fd, "Cannot stat /dev/console: %s", strerror(errno));
394 if (getuid() != sb.st_uid)
395 fatal (kc, fd, "Permission denied");
398 /* close down the new connection with a reasonable error message */
399 static void
400 close_connection(int fd, const char *message)
402 char buf[264]; /* max message */
403 char *p;
404 int lsb = 0;
405 size_t mlen;
406 ssize_t ret;
408 mlen = strlen(message);
409 if(mlen > 255)
410 mlen = 255;
412 /* read first part of connection packet, to get byte order */
413 if(read(fd, buf, 6) != 6) {
414 close(fd);
415 return;
417 if(buf[0] == 0x6c)
418 lsb++;
419 p = buf;
420 *p++ = 0; /* failed */
421 *p++ = mlen; /* length of message */
422 p += 4; /* skip protocol version */
423 p += 2; /* skip additional length */
424 memcpy(p, message, mlen); /* copy message */
425 p += mlen;
426 while((p - buf) % 4) /* pad to multiple of 4 bytes */
427 *p++ = 0;
429 /* now fill in length of additional data */
430 if(lsb) {
431 buf[6] = (p - buf - 8) / 4;
432 buf[7] = 0;
433 }else{
434 buf[6] = 0;
435 buf[7] = (p - buf - 8) / 4;
437 ret = write(fd, buf, p - buf);
438 close(fd);
443 * Handle a passive session on `sock'
446 static int
447 doit_passive (kx_context *kc,
448 int sock,
449 int flags,
450 int dispnr,
451 int nsockets,
452 struct x_socket *sockets,
453 int tcp_flag)
455 int tmp;
456 int len;
457 size_t rem;
458 u_char msg[1024], *p;
459 int error;
461 display_num = dispnr;
462 if (tcp_flag)
463 snprintf (display, display_size, "localhost:%u", display_num);
464 else
465 snprintf (display, display_size, ":%u", display_num);
466 error = create_and_write_cookie (xauthfile, xauthfile_size,
467 cookie, cookie_len);
468 if (error) {
469 cleanup(nsockets, sockets);
470 fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
471 return 1;
474 p = msg;
475 rem = sizeof(msg);
476 *p++ = ACK;
477 --rem;
479 len = strlen (display);
480 tmp = kx_put_int (len, p, rem, 4);
481 if (tmp < 0 || rem < len + 4) {
482 syslog (LOG_ERR, "doit: buffer too small");
483 cleanup(nsockets, sockets);
484 return 1;
486 p += tmp;
487 rem -= tmp;
489 memcpy (p, display, len);
490 p += len;
491 rem -= len;
493 len = strlen (xauthfile);
494 tmp = kx_put_int (len, p, rem, 4);
495 if (tmp < 0 || rem < len + 4) {
496 syslog (LOG_ERR, "doit: buffer too small");
497 cleanup(nsockets, sockets);
498 return 1;
500 p += tmp;
501 rem -= tmp;
503 memcpy (p, xauthfile, len);
504 p += len;
505 rem -= len;
507 if(kx_write (kc, sock, msg, p - msg) < 0) {
508 syslog (LOG_ERR, "write: %m");
509 cleanup(nsockets, sockets);
510 return 1;
512 for (;;) {
513 pid_t child;
514 int fd = -1;
515 fd_set fds;
516 int i;
517 int ret;
518 int cookiesp = TRUE;
520 FD_ZERO(&fds);
521 if (sock >= FD_SETSIZE) {
522 syslog (LOG_ERR, "fd too large");
523 cleanup(nsockets, sockets);
524 return 1;
527 FD_SET(sock, &fds);
528 for (i = 0; i < nsockets; ++i) {
529 if (sockets[i].fd >= FD_SETSIZE) {
530 syslog (LOG_ERR, "fd too large");
531 cleanup(nsockets, sockets);
532 return 1;
534 FD_SET(sockets[i].fd, &fds);
536 ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
537 if(ret <= 0)
538 continue;
539 if(FD_ISSET(sock, &fds)){
540 /* there are no processes left on the remote side
542 cleanup(nsockets, sockets);
543 exit(0);
544 } else if(ret) {
545 for (i = 0; i < nsockets; ++i) {
546 if (FD_ISSET(sockets[i].fd, &fds)) {
547 if (sockets[i].flags == TCP) {
548 struct sockaddr_storage __ss_peer;
549 struct sockaddr *peer = (struct sockaddr*)&__ss_peer;
550 socklen_t slen = sizeof(__ss_peer);
552 fd = accept (sockets[i].fd,
553 peer,
554 &slen);
555 if (fd < 0 && errno != EINTR)
556 syslog (LOG_ERR, "accept: %m");
558 /* XXX */
559 if (fd >= 0 && suspicious_address (fd, peer)) {
560 close (fd);
561 fd = -1;
562 errno = EINTR;
564 } else if(sockets[i].flags == UNIX_SOCKET) {
565 socklen_t zero = 0;
567 fd = accept (sockets[i].fd, NULL, &zero);
569 if (fd < 0 && errno != EINTR)
570 syslog (LOG_ERR, "accept: %m");
571 #ifdef MAY_HAVE_X11_PIPES
572 } else if(sockets[i].flags == STREAM_PIPE) {
574 * this code tries to handle the
575 * send fd-over-pipe stuff for
576 * solaris
579 struct strrecvfd strrecvfd;
581 ret = ioctl (sockets[i].fd,
582 I_RECVFD, &strrecvfd);
583 if (ret < 0 && errno != EINTR) {
584 syslog (LOG_ERR, "ioctl I_RECVFD: %m");
587 /* XXX */
588 if (ret == 0) {
589 if (strrecvfd.uid != getuid()) {
590 close (strrecvfd.fd);
591 fd = -1;
592 errno = EINTR;
593 } else {
594 fd = strrecvfd.fd;
595 cookiesp = FALSE;
598 #endif /* MAY_HAVE_X11_PIPES */
599 } else
600 abort ();
601 break;
605 if (fd < 0) {
606 if (errno == EINTR)
607 continue;
608 else
609 return 1;
612 child = fork ();
613 if (child < 0) {
614 syslog (LOG_ERR, "fork: %m");
615 if(errno != EAGAIN)
616 return 1;
617 close_connection(fd, strerror(errno));
618 } else if (child == 0) {
619 for (i = 0; i < nsockets; ++i)
620 close (sockets[i].fd);
621 return doit_conn (kc, fd, sock, flags, cookiesp);
622 } else {
623 close (fd);
629 * Handle an active session on `sock'
632 static int
633 doit_active (kx_context *kc,
634 int sock,
635 int flags,
636 int tcp_flag)
638 u_char msg[1024], *p;
640 check_user_console (kc, sock);
642 p = msg;
643 *p++ = ACK;
645 if(kx_write (kc, sock, msg, p - msg) < 0) {
646 syslog (LOG_ERR, "write: %m");
647 return 1;
649 for (;;) {
650 pid_t child;
651 int len;
653 len = kx_read (kc, sock, msg, sizeof(msg));
654 if (len < 0) {
655 syslog (LOG_ERR, "read: %m");
656 return 1;
658 p = (u_char *)msg;
659 if (*p != NEW_CONN) {
660 syslog (LOG_ERR, "bad_message: %d", *p);
661 return 1;
664 child = fork ();
665 if (child < 0) {
666 syslog (LOG_ERR, "fork: %m");
667 if (errno != EAGAIN)
668 return 1;
669 } else if (child == 0) {
670 return doit_conn (kc, sock, sock, flags, 1);
671 } else {
677 * Receive a connection on `sock' and process it.
680 static int
681 doit(int sock, int tcp_flag)
683 int ret;
684 kx_context context;
685 int dispnr;
686 int nsockets;
687 struct x_socket *sockets;
688 int flags;
690 flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
692 if (flags & PASSIVE) {
693 ret = doit_passive (&context, sock, flags, dispnr,
694 nsockets, sockets, tcp_flag);
695 } else {
696 ret = doit_active (&context, sock, flags, tcp_flag);
697 cleanup(nsockets, sockets);
699 context_destroy (&context);
700 return ret;
703 static char *port_str = NULL;
704 static int inetd_flag = 1;
705 static int tcp_flag = 0;
706 static int version_flag = 0;
707 static int help_flag = 0;
709 struct getargs args[] = {
710 { "inetd", 'i', arg_negative_flag, &inetd_flag,
711 "Not started from inetd", NULL },
712 { "tcp", 't', arg_flag, &tcp_flag, "Use TCP",
713 NULL },
714 { "port", 'p', arg_string, &port_str, "Use this port",
715 "port" },
716 { "version", 0, arg_flag, &version_flag, NULL, NULL },
717 { "help", 0, arg_flag, &help_flag, NULL, NULL }
720 static void
721 usage(int ret)
723 arg_printusage (args,
724 sizeof(args) / sizeof(args[0]),
725 NULL,
726 "host");
727 exit (ret);
731 * kxd - receive a forwarded X conncection
735 main (int argc, char **argv)
737 int port;
738 int optidx = 0;
740 setprogname (argv[0]);
741 roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
743 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
744 &optidx))
745 usage (1);
747 if (help_flag)
748 usage (0);
750 if (version_flag) {
751 print_version (NULL);
752 return 0;
755 if(port_str) {
756 struct servent *s = roken_getservbyname (port_str, "tcp");
758 if (s)
759 port = s->s_port;
760 else {
761 char *ptr;
763 port = strtol (port_str, &ptr, 10);
764 if (port == 0 && ptr == port_str)
765 errx (1, "bad port `%s'", port_str);
766 port = htons(port);
768 } else {
769 #if defined(KRB5)
770 port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT);
771 #else
772 #error define KRB5
773 #endif
776 if (!inetd_flag)
777 mini_inetd (port, NULL);
779 signal (SIGCHLD, childhandler);
780 return doit(STDIN_FILENO, tcp_flag);