This commit was manufactured by cvs2svn to create tag
[heimdal.git] / appl / kx / kxd.c
blobb6e3deaa176febaf376b6438ea88c2d50bfa2beb
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 addrlen = sizeof(kc->__ss_this);
125 kc->thisaddr = (struct sockaddr*)&kc->__ss_this;
126 if (getsockname (sock, kc->thisaddr, &addrlen) < 0) {
127 syslog (LOG_ERR, "getsockname: %m");
128 exit (1);
130 kc->thisaddr_len = addrlen;
131 addrlen = sizeof(kc->__ss_that);
132 kc->thataddr = (struct sockaddr*)&kc->__ss_that;
133 if (getpeername (sock, kc->thataddr, &addrlen) < 0) {
134 syslog (LOG_ERR, "getpeername: %m");
135 exit (1);
137 kc->thataddr_len = addrlen;
139 getnameinfo_verified (kc->thataddr,
140 kc->thataddr_len,
141 remotehost, sizeof(remotehost),
142 NULL, 0, 0);
144 if (net_read (sock, msg, 4) != 4) {
145 syslog (LOG_ERR, "read: %m");
146 exit (1);
149 #ifdef KRB5
150 if (ret && recv_v5_auth (kc, sock, msg) == 0)
151 ret = 0;
152 #endif
153 #ifdef KRB4
154 if (ret && recv_v4_auth (kc, sock, msg) == 0)
155 ret = 0;
156 #endif
157 if (ret) {
158 syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x",
159 msg[0], msg[1], msg[2], msg[3]);
160 exit (1);
163 len = kx_read (kc, sock, msg, sizeof(msg));
164 if (len < 0) {
165 syslog (LOG_ERR, "kx_read failed");
166 exit (1);
168 p = (u_char *)msg;
169 if (*p != INIT)
170 fatal(kc, sock, "Bad message");
171 p++;
172 p += krb_get_int (p, &tmp32, 4, 0);
173 len = min(sizeof(user), tmp32);
174 memcpy (user, p, len);
175 p += tmp32;
176 user[len] = '\0';
178 passwd = k_getpwnam (user);
179 if (passwd == NULL)
180 fatal (kc, sock, "cannot find uid for %s", user);
182 if (context_userok (kc, user) != 0)
183 fatal (kc, sock, "%s not allowed to login as %s",
184 kc->user, user);
186 flags = *p++;
188 if (flags & PASSIVE) {
189 pid_t pid;
190 int tmp;
192 tmp = get_xsockets (nsockets, sockets, tcp_flag);
193 if (tmp < 0) {
194 fatal (kc, sock, "Cannot create X socket(s): %s",
195 strerror(errno));
197 *dispnr = tmp;
199 if (chown_xsockets (*nsockets, *sockets,
200 passwd->pw_uid, passwd->pw_gid)) {
201 cleanup (*nsockets, *sockets);
202 fatal (kc, sock, "Cannot chown sockets: %s",
203 strerror(errno));
206 pid = fork();
207 if (pid == -1) {
208 cleanup (*nsockets, *sockets);
209 fatal (kc, sock, "fork: %s", strerror(errno));
210 } else if (pid != 0) {
211 wait_on_pid = pid;
212 while (!done)
213 pause ();
214 cleanup (*nsockets, *sockets);
215 exit (0);
219 if (setgid (passwd->pw_gid) ||
220 initgroups(passwd->pw_name, passwd->pw_gid) ||
221 #ifdef HAVE_GETUDBNAM /* XXX this happens on crays */
222 setjob(passwd->pw_uid, 0) == -1 ||
223 #endif
224 setuid(passwd->pw_uid)) {
225 syslog(LOG_ERR, "setting uid/groups: %m");
226 fatal (kc, sock, "cannot set uid");
229 ret = getnameinfo(kc->thataddr, kc->thataddr_len,
230 remoteaddr, sizeof(remoteaddr),
231 NULL, 0, NI_NUMERICHOST);
232 if (ret != 0)
233 fatal (kc, sock, "getnameinfo failed: %s", gai_strerror(ret));
235 syslog (LOG_INFO, "from %s(%s): %s -> %s",
236 remotehost, remoteaddr,
237 kc->user, user);
238 umask(077);
239 if (!(flags & PASSIVE)) {
240 p += krb_get_int (p, &tmp32, 4, 0);
241 len = min(tmp32, display_size);
242 memcpy (display, p, len);
243 display[len] = '\0';
244 p += tmp32;
245 p += krb_get_int (p, &tmp32, 4, 0);
246 len = min(tmp32, xauthfile_size);
247 memcpy (xauthfile, p, len);
248 xauthfile[len] = '\0';
249 p += tmp32;
251 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
252 if (flags & KEEP_ALIVE) {
253 int one = 1;
255 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
256 sizeof(one));
258 #endif
259 return flags;
266 static int
267 passive_session (kx_context *kc, int fd, int sock, int cookiesp)
269 if (verify_and_remove_cookies (fd, sock, cookiesp))
270 return 1;
271 else
272 return copy_encrypted (kc, fd, sock);
279 static int
280 active_session (kx_context *kc, int fd, int sock, int cookiesp)
282 fd = connect_local_xsocket(0);
284 if (replace_cookie (fd, sock, xauthfile, cookiesp))
285 return 1;
286 else
287 return copy_encrypted (kc, fd, sock);
291 * Handle a new connection.
294 static int
295 doit_conn (kx_context *kc,
296 int fd, int meta_sock, int flags, int cookiesp)
298 int sock, sock2, port;
299 struct sockaddr_storage __ss_addr;
300 struct sockaddr *addr = (struct sockaddr*)&__ss_addr;
301 struct sockaddr_storage __ss_thisaddr;
302 struct sockaddr *thisaddr = (struct sockaddr*)&__ss_thisaddr;
303 socklen_t addrlen;
304 u_char msg[1024], *p;
306 sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0);
307 if (sock < 0) {
308 syslog (LOG_ERR, "socket: %m");
309 return 1;
311 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
313 int one = 1;
314 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));
316 #endif
317 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
318 if (flags & KEEP_ALIVE) {
319 int one = 1;
321 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
322 sizeof(one));
324 #endif
325 memset (&__ss_addr, 0, sizeof(__ss_addr));
326 addr->sa_family = kc->thisaddr->sa_family;
327 if (kc->thisaddr_len > sizeof(__ss_addr)) {
328 syslog(LOG_ERR, "error in af");
329 return 1;
331 if (bind (sock, addr, kc->thisaddr_len) < 0) {
332 syslog (LOG_ERR, "bind: %m");
333 return 1;
335 addrlen = sizeof(__ss_addr);
336 if (getsockname (sock, addr, &addrlen) < 0) {
337 syslog (LOG_ERR, "getsockname: %m");
338 return 1;
340 if (listen (sock, SOMAXCONN) < 0) {
341 syslog (LOG_ERR, "listen: %m");
342 return 1;
344 port = socket_get_port(addr);
346 p = msg;
347 *p++ = NEW_CONN;
348 p += KRB_PUT_INT (ntohs(port), p, 4, 4);
350 if (kx_write (kc, meta_sock, msg, p - msg) < 0) {
351 syslog (LOG_ERR, "write: %m");
352 return 1;
355 addrlen = sizeof(__ss_thisaddr);
356 sock2 = accept (sock, thisaddr, &addrlen);
357 if (sock2 < 0) {
358 syslog (LOG_ERR, "accept: %m");
359 return 1;
361 close (sock);
362 close (meta_sock);
364 if (flags & PASSIVE)
365 return passive_session (kc, fd, sock2, cookiesp);
366 else
367 return active_session (kc, fd, sock2, cookiesp);
371 * Is the current user the owner of the console?
374 static void
375 check_user_console (kx_context *kc, int fd)
377 struct stat sb;
379 if (stat ("/dev/console", &sb) < 0)
380 fatal (kc, fd, "Cannot stat /dev/console: %s", strerror(errno));
381 if (getuid() != sb.st_uid)
382 fatal (kc, fd, "Permission denied");
385 /* close down the new connection with a reasonable error message */
386 static void
387 close_connection(int fd, const char *message)
389 char buf[264]; /* max message */
390 char *p;
391 int lsb = 0;
392 size_t mlen;
394 mlen = strlen(message);
395 if(mlen > 255)
396 mlen = 255;
398 /* read first part of connection packet, to get byte order */
399 if(read(fd, buf, 6) != 6) {
400 close(fd);
401 return;
403 if(buf[0] == 0x6c)
404 lsb++;
405 p = buf;
406 *p++ = 0; /* failed */
407 *p++ = mlen; /* length of message */
408 p += 4; /* skip protocol version */
409 p += 2; /* skip additional length */
410 memcpy(p, message, mlen); /* copy message */
411 p += mlen;
412 while((p - buf) % 4) /* pad to multiple of 4 bytes */
413 *p++ = 0;
415 /* now fill in length of additional data */
416 if(lsb) {
417 buf[6] = (p - buf - 8) / 4;
418 buf[7] = 0;
419 }else{
420 buf[6] = 0;
421 buf[7] = (p - buf - 8) / 4;
423 write(fd, buf, p - buf);
424 close(fd);
429 * Handle a passive session on `sock'
432 static int
433 doit_passive (kx_context *kc,
434 int sock,
435 int flags,
436 int dispnr,
437 int nsockets,
438 struct x_socket *sockets,
439 int tcp_flag)
441 int tmp;
442 int len;
443 size_t rem;
444 u_char msg[1024], *p;
445 int error;
447 display_num = dispnr;
448 if (tcp_flag)
449 snprintf (display, display_size, "localhost:%u", display_num);
450 else
451 snprintf (display, display_size, ":%u", display_num);
452 error = create_and_write_cookie (xauthfile, xauthfile_size,
453 cookie, cookie_len);
454 if (error) {
455 cleanup(nsockets, sockets);
456 fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
457 return 1;
460 p = msg;
461 rem = sizeof(msg);
462 *p++ = ACK;
463 --rem;
465 len = strlen (display);
466 tmp = KRB_PUT_INT (len, p, rem, 4);
467 if (tmp < 0 || rem < len + 4) {
468 syslog (LOG_ERR, "doit: buffer too small");
469 cleanup(nsockets, sockets);
470 return 1;
472 p += tmp;
473 rem -= tmp;
475 memcpy (p, display, len);
476 p += len;
477 rem -= len;
479 len = strlen (xauthfile);
480 tmp = KRB_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, xauthfile, len);
490 p += len;
491 rem -= len;
493 if(kx_write (kc, sock, msg, p - msg) < 0) {
494 syslog (LOG_ERR, "write: %m");
495 cleanup(nsockets, sockets);
496 return 1;
498 for (;;) {
499 pid_t child;
500 int fd = -1;
501 fd_set fds;
502 int i;
503 int ret;
504 int cookiesp = TRUE;
506 FD_ZERO(&fds);
507 if (sock >= FD_SETSIZE) {
508 syslog (LOG_ERR, "fd too large");
509 cleanup(nsockets, sockets);
510 return 1;
513 FD_SET(sock, &fds);
514 for (i = 0; i < nsockets; ++i) {
515 if (sockets[i].fd >= FD_SETSIZE) {
516 syslog (LOG_ERR, "fd too large");
517 cleanup(nsockets, sockets);
518 return 1;
520 FD_SET(sockets[i].fd, &fds);
522 ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
523 if(ret <= 0)
524 continue;
525 if(FD_ISSET(sock, &fds)){
526 /* there are no processes left on the remote side
528 cleanup(nsockets, sockets);
529 exit(0);
530 } else if(ret) {
531 for (i = 0; i < nsockets; ++i) {
532 if (FD_ISSET(sockets[i].fd, &fds)) {
533 if (sockets[i].flags == TCP) {
534 struct sockaddr_storage __ss_peer;
535 struct sockaddr *peer = (struct sockaddr*)&__ss_peer;
536 socklen_t len = sizeof(__ss_peer);
538 fd = accept (sockets[i].fd,
539 peer,
540 &len);
541 if (fd < 0 && errno != EINTR)
542 syslog (LOG_ERR, "accept: %m");
544 /* XXX */
545 if (fd >= 0 && suspicious_address (fd, peer)) {
546 close (fd);
547 fd = -1;
548 errno = EINTR;
550 } else if(sockets[i].flags == UNIX_SOCKET) {
551 socklen_t zero = 0;
553 fd = accept (sockets[i].fd, NULL, &zero);
555 if (fd < 0 && errno != EINTR)
556 syslog (LOG_ERR, "accept: %m");
557 #ifdef MAY_HAVE_X11_PIPES
558 } else if(sockets[i].flags == STREAM_PIPE) {
560 * this code tries to handle the
561 * send fd-over-pipe stuff for
562 * solaris
565 struct strrecvfd strrecvfd;
567 ret = ioctl (sockets[i].fd,
568 I_RECVFD, &strrecvfd);
569 if (ret < 0 && errno != EINTR) {
570 syslog (LOG_ERR, "ioctl I_RECVFD: %m");
573 /* XXX */
574 if (ret == 0) {
575 if (strrecvfd.uid != getuid()) {
576 close (strrecvfd.fd);
577 fd = -1;
578 errno = EINTR;
579 } else {
580 fd = strrecvfd.fd;
581 cookiesp = FALSE;
584 #endif /* MAY_HAVE_X11_PIPES */
585 } else
586 abort ();
587 break;
591 if (fd < 0) {
592 if (errno == EINTR)
593 continue;
594 else
595 return 1;
598 child = fork ();
599 if (child < 0) {
600 syslog (LOG_ERR, "fork: %m");
601 if(errno != EAGAIN)
602 return 1;
603 close_connection(fd, strerror(errno));
604 } else if (child == 0) {
605 for (i = 0; i < nsockets; ++i)
606 close (sockets[i].fd);
607 return doit_conn (kc, fd, sock, flags, cookiesp);
608 } else {
609 close (fd);
615 * Handle an active session on `sock'
618 static int
619 doit_active (kx_context *kc,
620 int sock,
621 int flags,
622 int tcp_flag)
624 u_char msg[1024], *p;
626 check_user_console (kc, sock);
628 p = msg;
629 *p++ = ACK;
631 if(kx_write (kc, sock, msg, p - msg) < 0) {
632 syslog (LOG_ERR, "write: %m");
633 return 1;
635 for (;;) {
636 pid_t child;
637 int len;
639 len = kx_read (kc, sock, msg, sizeof(msg));
640 if (len < 0) {
641 syslog (LOG_ERR, "read: %m");
642 return 1;
644 p = (u_char *)msg;
645 if (*p != NEW_CONN) {
646 syslog (LOG_ERR, "bad_message: %d", *p);
647 return 1;
650 child = fork ();
651 if (child < 0) {
652 syslog (LOG_ERR, "fork: %m");
653 if (errno != EAGAIN)
654 return 1;
655 } else if (child == 0) {
656 return doit_conn (kc, sock, sock, flags, 1);
657 } else {
663 * Receive a connection on `sock' and process it.
666 static int
667 doit(int sock, int tcp_flag)
669 int ret;
670 kx_context context;
671 int dispnr;
672 int nsockets;
673 struct x_socket *sockets;
674 int flags;
676 flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
678 if (flags & PASSIVE)
679 ret = doit_passive (&context, sock, flags, dispnr,
680 nsockets, sockets, tcp_flag);
681 else
682 ret = doit_active (&context, sock, flags, tcp_flag);
683 context_destroy (&context);
684 return ret;
687 static char *port_str = NULL;
688 static int inetd_flag = 1;
689 static int tcp_flag = 0;
690 static int version_flag = 0;
691 static int help_flag = 0;
693 struct getargs args[] = {
694 { "inetd", 'i', arg_negative_flag, &inetd_flag,
695 "Not started from inetd" },
696 { "tcp", 't', arg_flag, &tcp_flag, "Use TCP" },
697 { "port", 'p', arg_string, &port_str, "Use this port",
698 "port" },
699 { "version", 0, arg_flag, &version_flag },
700 { "help", 0, arg_flag, &help_flag }
703 static void
704 usage(int ret)
706 arg_printusage (args,
707 sizeof(args) / sizeof(args[0]),
708 NULL,
709 "host");
710 exit (ret);
714 * kxd - receive a forwarded X conncection
718 main (int argc, char **argv)
720 int port;
721 int optind = 0;
723 setprogname (argv[0]);
724 roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
726 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
727 &optind))
728 usage (1);
730 if (help_flag)
731 usage (0);
733 if (version_flag) {
734 print_version (NULL);
735 return 0;
738 if(port_str) {
739 struct servent *s = roken_getservbyname (port_str, "tcp");
741 if (s)
742 port = s->s_port;
743 else {
744 char *ptr;
746 port = strtol (port_str, &ptr, 10);
747 if (port == 0 && ptr == port_str)
748 errx (1, "bad port `%s'", port_str);
749 port = htons(port);
751 } else {
752 #if defined(KRB5)
753 port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT);
754 #elif defined(KRB4)
755 port = k_getportbyname ("kx", "tcp", htons(KX_PORT));
756 #else
757 #error define KRB4 or KRB5
758 #endif
761 if (!inetd_flag)
762 mini_inetd (port);
764 signal (SIGCHLD, childhandler);
765 return doit(STDIN_FILENO, tcp_flag);