Include ec*.h files
[heimdal.git] / appl / kx / kxd.c
blob65bd1a18f9a55be1f2749ca140810abd3622d885
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 addr->sa_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;
407 mlen = strlen(message);
408 if(mlen > 255)
409 mlen = 255;
411 /* read first part of connection packet, to get byte order */
412 if(read(fd, buf, 6) != 6) {
413 close(fd);
414 return;
416 if(buf[0] == 0x6c)
417 lsb++;
418 p = buf;
419 *p++ = 0; /* failed */
420 *p++ = mlen; /* length of message */
421 p += 4; /* skip protocol version */
422 p += 2; /* skip additional length */
423 memcpy(p, message, mlen); /* copy message */
424 p += mlen;
425 while((p - buf) % 4) /* pad to multiple of 4 bytes */
426 *p++ = 0;
428 /* now fill in length of additional data */
429 if(lsb) {
430 buf[6] = (p - buf - 8) / 4;
431 buf[7] = 0;
432 }else{
433 buf[6] = 0;
434 buf[7] = (p - buf - 8) / 4;
436 write(fd, buf, p - buf);
437 close(fd);
442 * Handle a passive session on `sock'
445 static int
446 doit_passive (kx_context *kc,
447 int sock,
448 int flags,
449 int dispnr,
450 int nsockets,
451 struct x_socket *sockets,
452 int tcp_flag)
454 int tmp;
455 int len;
456 size_t rem;
457 u_char msg[1024], *p;
458 int error;
460 display_num = dispnr;
461 if (tcp_flag)
462 snprintf (display, display_size, "localhost:%u", display_num);
463 else
464 snprintf (display, display_size, ":%u", display_num);
465 error = create_and_write_cookie (xauthfile, xauthfile_size,
466 cookie, cookie_len);
467 if (error) {
468 cleanup(nsockets, sockets);
469 fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
470 return 1;
473 p = msg;
474 rem = sizeof(msg);
475 *p++ = ACK;
476 --rem;
478 len = strlen (display);
479 tmp = kx_put_int (len, p, rem, 4);
480 if (tmp < 0 || rem < len + 4) {
481 syslog (LOG_ERR, "doit: buffer too small");
482 cleanup(nsockets, sockets);
483 return 1;
485 p += tmp;
486 rem -= tmp;
488 memcpy (p, display, len);
489 p += len;
490 rem -= len;
492 len = strlen (xauthfile);
493 tmp = kx_put_int (len, p, rem, 4);
494 if (tmp < 0 || rem < len + 4) {
495 syslog (LOG_ERR, "doit: buffer too small");
496 cleanup(nsockets, sockets);
497 return 1;
499 p += tmp;
500 rem -= tmp;
502 memcpy (p, xauthfile, len);
503 p += len;
504 rem -= len;
506 if(kx_write (kc, sock, msg, p - msg) < 0) {
507 syslog (LOG_ERR, "write: %m");
508 cleanup(nsockets, sockets);
509 return 1;
511 for (;;) {
512 pid_t child;
513 int fd = -1;
514 fd_set fds;
515 int i;
516 int ret;
517 int cookiesp = TRUE;
519 FD_ZERO(&fds);
520 if (sock >= FD_SETSIZE) {
521 syslog (LOG_ERR, "fd too large");
522 cleanup(nsockets, sockets);
523 return 1;
526 FD_SET(sock, &fds);
527 for (i = 0; i < nsockets; ++i) {
528 if (sockets[i].fd >= FD_SETSIZE) {
529 syslog (LOG_ERR, "fd too large");
530 cleanup(nsockets, sockets);
531 return 1;
533 FD_SET(sockets[i].fd, &fds);
535 ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
536 if(ret <= 0)
537 continue;
538 if(FD_ISSET(sock, &fds)){
539 /* there are no processes left on the remote side
541 cleanup(nsockets, sockets);
542 exit(0);
543 } else if(ret) {
544 for (i = 0; i < nsockets; ++i) {
545 if (FD_ISSET(sockets[i].fd, &fds)) {
546 if (sockets[i].flags == TCP) {
547 struct sockaddr_storage __ss_peer;
548 struct sockaddr *peer = (struct sockaddr*)&__ss_peer;
549 socklen_t slen = sizeof(__ss_peer);
551 fd = accept (sockets[i].fd,
552 peer,
553 &slen);
554 if (fd < 0 && errno != EINTR)
555 syslog (LOG_ERR, "accept: %m");
557 /* XXX */
558 if (fd >= 0 && suspicious_address (fd, peer)) {
559 close (fd);
560 fd = -1;
561 errno = EINTR;
563 } else if(sockets[i].flags == UNIX_SOCKET) {
564 socklen_t zero = 0;
566 fd = accept (sockets[i].fd, NULL, &zero);
568 if (fd < 0 && errno != EINTR)
569 syslog (LOG_ERR, "accept: %m");
570 #ifdef MAY_HAVE_X11_PIPES
571 } else if(sockets[i].flags == STREAM_PIPE) {
573 * this code tries to handle the
574 * send fd-over-pipe stuff for
575 * solaris
578 struct strrecvfd strrecvfd;
580 ret = ioctl (sockets[i].fd,
581 I_RECVFD, &strrecvfd);
582 if (ret < 0 && errno != EINTR) {
583 syslog (LOG_ERR, "ioctl I_RECVFD: %m");
586 /* XXX */
587 if (ret == 0) {
588 if (strrecvfd.uid != getuid()) {
589 close (strrecvfd.fd);
590 fd = -1;
591 errno = EINTR;
592 } else {
593 fd = strrecvfd.fd;
594 cookiesp = FALSE;
597 #endif /* MAY_HAVE_X11_PIPES */
598 } else
599 abort ();
600 break;
604 if (fd < 0) {
605 if (errno == EINTR)
606 continue;
607 else
608 return 1;
611 child = fork ();
612 if (child < 0) {
613 syslog (LOG_ERR, "fork: %m");
614 if(errno != EAGAIN)
615 return 1;
616 close_connection(fd, strerror(errno));
617 } else if (child == 0) {
618 for (i = 0; i < nsockets; ++i)
619 close (sockets[i].fd);
620 return doit_conn (kc, fd, sock, flags, cookiesp);
621 } else {
622 close (fd);
628 * Handle an active session on `sock'
631 static int
632 doit_active (kx_context *kc,
633 int sock,
634 int flags,
635 int tcp_flag)
637 u_char msg[1024], *p;
639 check_user_console (kc, sock);
641 p = msg;
642 *p++ = ACK;
644 if(kx_write (kc, sock, msg, p - msg) < 0) {
645 syslog (LOG_ERR, "write: %m");
646 return 1;
648 for (;;) {
649 pid_t child;
650 int len;
652 len = kx_read (kc, sock, msg, sizeof(msg));
653 if (len < 0) {
654 syslog (LOG_ERR, "read: %m");
655 return 1;
657 p = (u_char *)msg;
658 if (*p != NEW_CONN) {
659 syslog (LOG_ERR, "bad_message: %d", *p);
660 return 1;
663 child = fork ();
664 if (child < 0) {
665 syslog (LOG_ERR, "fork: %m");
666 if (errno != EAGAIN)
667 return 1;
668 } else if (child == 0) {
669 return doit_conn (kc, sock, sock, flags, 1);
670 } else {
676 * Receive a connection on `sock' and process it.
679 static int
680 doit(int sock, int tcp_flag)
682 int ret;
683 kx_context context;
684 int dispnr;
685 int nsockets;
686 struct x_socket *sockets;
687 int flags;
689 flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
691 if (flags & PASSIVE) {
692 ret = doit_passive (&context, sock, flags, dispnr,
693 nsockets, sockets, tcp_flag);
694 } else {
695 ret = doit_active (&context, sock, flags, tcp_flag);
696 cleanup(nsockets, sockets);
698 context_destroy (&context);
699 return ret;
702 static char *port_str = NULL;
703 static int inetd_flag = 1;
704 static int tcp_flag = 0;
705 static int version_flag = 0;
706 static int help_flag = 0;
708 struct getargs args[] = {
709 { "inetd", 'i', arg_negative_flag, &inetd_flag,
710 "Not started from inetd" },
711 { "tcp", 't', arg_flag, &tcp_flag, "Use TCP" },
712 { "port", 'p', arg_string, &port_str, "Use this port",
713 "port" },
714 { "version", 0, arg_flag, &version_flag },
715 { "help", 0, arg_flag, &help_flag }
718 static void
719 usage(int ret)
721 arg_printusage (args,
722 sizeof(args) / sizeof(args[0]),
723 NULL,
724 "host");
725 exit (ret);
729 * kxd - receive a forwarded X conncection
733 main (int argc, char **argv)
735 int port;
736 int optidx = 0;
738 setprogname (argv[0]);
739 roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
741 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
742 &optidx))
743 usage (1);
745 if (help_flag)
746 usage (0);
748 if (version_flag) {
749 print_version (NULL);
750 return 0;
753 if(port_str) {
754 struct servent *s = roken_getservbyname (port_str, "tcp");
756 if (s)
757 port = s->s_port;
758 else {
759 char *ptr;
761 port = strtol (port_str, &ptr, 10);
762 if (port == 0 && ptr == port_str)
763 errx (1, "bad port `%s'", port_str);
764 port = htons(port);
766 } else {
767 #if defined(KRB5)
768 port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT);
769 #else
770 #error define KRB5
771 #endif
774 if (!inetd_flag)
775 mini_inetd (port);
777 signal (SIGCHLD, childhandler);
778 return doit(STDIN_FILENO, tcp_flag);