No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / kx / kxd.c
blob8259e928c6af06cf9e8f7361329eebddce571915
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("$Heimdal: kxd.c 20452 2007-04-19 20:04:19Z lha $"
37 "$NetBSD$");
39 static pid_t wait_on_pid = -1;
40 static int done = 0;
43 * Signal handler that justs waits for the children when they die.
46 static RETSIGTYPE
47 childhandler (int sig)
49 pid_t pid;
50 int status;
52 do {
53 pid = waitpid (-1, &status, WNOHANG|WUNTRACED);
54 if (pid > 0 && pid == wait_on_pid)
55 done = 1;
56 } while(pid > 0);
57 signal (SIGCHLD, childhandler);
58 SIGRETURN(0);
62 * Print the error message `format' and `...' on fd and die.
65 void
66 fatal (kx_context *kc, int fd, char *format, ...)
68 u_char msg[1024];
69 u_char *p;
70 va_list args;
71 int len;
73 va_start(args, format);
74 p = msg;
75 *p++ = ERROR;
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);
80 p += len;
81 kx_write (kc, fd, msg, p - msg);
82 va_end(args);
83 exit (1);
87 * Remove all sockets and cookie files.
90 static void
91 cleanup(int nsockets, struct x_socket *sockets)
93 int i;
95 if(xauthfile[0])
96 unlink(xauthfile);
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'.
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 #ifdef KRB4
160 if (ret && recv_v4_auth (kc, sock, msg) == 0)
161 ret = 0;
162 #endif
163 if (ret) {
164 syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x",
165 msg[0], msg[1], msg[2], msg[3]);
166 exit (1);
169 len = kx_read (kc, sock, msg, sizeof(msg));
170 if (len < 0) {
171 syslog (LOG_ERR, "kx_read failed");
172 exit (1);
174 p = (u_char *)msg;
175 if (*p != INIT)
176 fatal(kc, sock, "Bad message");
177 p++;
178 p += kx_get_int (p, &tmp32, 4, 0);
179 len = min(sizeof(user), tmp32);
180 memcpy (user, p, len);
181 p += tmp32;
182 user[len] = '\0';
184 passwd = k_getpwnam (user);
185 if (passwd == NULL)
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",
190 kc->user, user);
192 flags = *p++;
194 if (flags & PASSIVE) {
195 pid_t pid;
196 int tmp;
198 tmp = get_xsockets (nsockets, sockets, tcp_flag);
199 if (tmp < 0) {
200 fatal (kc, sock, "Cannot create X socket(s): %s",
201 strerror(errno));
203 *dispnr = tmp;
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",
209 strerror(errno));
212 pid = fork();
213 if (pid == -1) {
214 cleanup (*nsockets, *sockets);
215 fatal (kc, sock, "fork: %s", strerror(errno));
216 } else if (pid != 0) {
217 wait_on_pid = pid;
218 while (!done)
219 pause ();
220 cleanup (*nsockets, *sockets);
221 exit (0);
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 ||
229 #endif
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);
238 if (ret != 0)
239 fatal (kc, sock, "getnameinfo failed: %s", gai_strerror(ret));
241 syslog (LOG_INFO, "from %s(%s): %s -> %s",
242 remotehost, remoteaddr,
243 kc->user, user);
244 umask(077);
245 if (!(flags & PASSIVE)) {
246 p += kx_get_int (p, &tmp32, 4, 0);
247 len = min(tmp32, display_size);
248 memcpy (display, p, len);
249 display[len] = '\0';
250 p += tmp32;
251 p += kx_get_int (p, &tmp32, 4, 0);
252 len = min(tmp32, xauthfile_size);
253 memcpy (xauthfile, p, len);
254 xauthfile[len] = '\0';
255 p += tmp32;
257 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
258 if (flags & KEEP_ALIVE) {
259 int one = 1;
261 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
262 sizeof(one));
264 #endif
265 return flags;
272 static int
273 passive_session (kx_context *kc, int fd, int sock, int cookiesp)
275 if (verify_and_remove_cookies (fd, sock, cookiesp))
276 return 1;
277 else
278 return copy_encrypted (kc, fd, sock);
285 static int
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))
291 return 1;
292 else
293 return copy_encrypted (kc, fd, sock);
297 * Handle a new connection.
300 static int
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;
309 socklen_t addrlen;
310 u_char msg[1024], *p;
312 sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0);
313 if (sock < 0) {
314 syslog (LOG_ERR, "socket: %m");
315 return 1;
317 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
319 int one = 1;
320 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));
322 #endif
323 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
324 if (flags & KEEP_ALIVE) {
325 int one = 1;
327 setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
328 sizeof(one));
330 #endif
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");
335 return 1;
337 if (bind (sock, addr, kc->thisaddr_len) < 0) {
338 syslog (LOG_ERR, "bind: %m");
339 return 1;
341 addrlen = sizeof(__ss_addr);
342 if (getsockname (sock, addr, &addrlen) < 0) {
343 syslog (LOG_ERR, "getsockname: %m");
344 return 1;
346 if (listen (sock, SOMAXCONN) < 0) {
347 syslog (LOG_ERR, "listen: %m");
348 return 1;
350 port = socket_get_port(addr);
352 p = msg;
353 *p++ = NEW_CONN;
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");
358 return 1;
361 addrlen = sizeof(__ss_thisaddr);
362 sock2 = accept (sock, thisaddr, &addrlen);
363 if (sock2 < 0) {
364 syslog (LOG_ERR, "accept: %m");
365 return 1;
367 close (sock);
368 close (meta_sock);
370 if (flags & PASSIVE)
371 return passive_session (kc, fd, sock2, cookiesp);
372 else
373 return active_session (kc, fd, sock2, cookiesp);
377 * Is the current user the owner of the console?
380 static void
381 check_user_console (kx_context *kc, int fd)
383 struct stat sb;
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 */
392 static void
393 close_connection(int fd, const char *message)
395 char buf[264]; /* max message */
396 char *p;
397 int lsb = 0;
398 size_t mlen;
400 mlen = strlen(message);
401 if(mlen > 255)
402 mlen = 255;
404 /* read first part of connection packet, to get byte order */
405 if(read(fd, buf, 6) != 6) {
406 close(fd);
407 return;
409 if(buf[0] == 0x6c)
410 lsb++;
411 p = buf;
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 */
417 p += mlen;
418 while((p - buf) % 4) /* pad to multiple of 4 bytes */
419 *p++ = 0;
421 /* now fill in length of additional data */
422 if(lsb) {
423 buf[6] = (p - buf - 8) / 4;
424 buf[7] = 0;
425 }else{
426 buf[6] = 0;
427 buf[7] = (p - buf - 8) / 4;
429 write(fd, buf, p - buf);
430 close(fd);
435 * Handle a passive session on `sock'
438 static int
439 doit_passive (kx_context *kc,
440 int sock,
441 int flags,
442 int dispnr,
443 int nsockets,
444 struct x_socket *sockets,
445 int tcp_flag)
447 int tmp;
448 int len;
449 size_t rem;
450 u_char msg[1024], *p;
451 int error;
453 display_num = dispnr;
454 if (tcp_flag)
455 snprintf (display, display_size, "localhost:%u", display_num);
456 else
457 snprintf (display, display_size, ":%u", display_num);
458 error = create_and_write_cookie (xauthfile, xauthfile_size,
459 cookie, cookie_len);
460 if (error) {
461 cleanup(nsockets, sockets);
462 fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
463 return 1;
466 p = msg;
467 rem = sizeof(msg);
468 *p++ = ACK;
469 --rem;
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);
476 return 1;
478 p += tmp;
479 rem -= tmp;
481 memcpy (p, display, len);
482 p += len;
483 rem -= 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);
490 return 1;
492 p += tmp;
493 rem -= tmp;
495 memcpy (p, xauthfile, len);
496 p += len;
497 rem -= len;
499 if(kx_write (kc, sock, msg, p - msg) < 0) {
500 syslog (LOG_ERR, "write: %m");
501 cleanup(nsockets, sockets);
502 return 1;
504 for (;;) {
505 pid_t child;
506 int fd = -1;
507 fd_set fds;
508 int i;
509 int ret;
510 int cookiesp = TRUE;
512 FD_ZERO(&fds);
513 if (sock >= FD_SETSIZE) {
514 syslog (LOG_ERR, "fd too large");
515 cleanup(nsockets, sockets);
516 return 1;
519 FD_SET(sock, &fds);
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);
524 return 1;
526 FD_SET(sockets[i].fd, &fds);
528 ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
529 if(ret <= 0)
530 continue;
531 if(FD_ISSET(sock, &fds)){
532 /* there are no processes left on the remote side
534 cleanup(nsockets, sockets);
535 exit(0);
536 } else if(ret) {
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,
545 peer,
546 &slen);
547 if (fd < 0 && errno != EINTR)
548 syslog (LOG_ERR, "accept: %m");
550 /* XXX */
551 if (fd >= 0 && suspicious_address (fd, peer)) {
552 close (fd);
553 fd = -1;
554 errno = EINTR;
556 } else if(sockets[i].flags == UNIX_SOCKET) {
557 socklen_t zero = 0;
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
568 * solaris
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");
579 /* XXX */
580 if (ret == 0) {
581 if (strrecvfd.uid != getuid()) {
582 close (strrecvfd.fd);
583 fd = -1;
584 errno = EINTR;
585 } else {
586 fd = strrecvfd.fd;
587 cookiesp = FALSE;
590 #endif /* MAY_HAVE_X11_PIPES */
591 } else
592 abort ();
593 break;
597 if (fd < 0) {
598 if (errno == EINTR)
599 continue;
600 else
601 return 1;
604 child = fork ();
605 if (child < 0) {
606 syslog (LOG_ERR, "fork: %m");
607 if(errno != EAGAIN)
608 return 1;
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);
614 } else {
615 close (fd);
621 * Handle an active session on `sock'
624 static int
625 doit_active (kx_context *kc,
626 int sock,
627 int flags,
628 int tcp_flag)
630 u_char msg[1024], *p;
632 check_user_console (kc, sock);
634 p = msg;
635 *p++ = ACK;
637 if(kx_write (kc, sock, msg, p - msg) < 0) {
638 syslog (LOG_ERR, "write: %m");
639 return 1;
641 for (;;) {
642 pid_t child;
643 int len;
645 len = kx_read (kc, sock, msg, sizeof(msg));
646 if (len < 0) {
647 syslog (LOG_ERR, "read: %m");
648 return 1;
650 p = (u_char *)msg;
651 if (*p != NEW_CONN) {
652 syslog (LOG_ERR, "bad_message: %d", *p);
653 return 1;
656 child = fork ();
657 if (child < 0) {
658 syslog (LOG_ERR, "fork: %m");
659 if (errno != EAGAIN)
660 return 1;
661 } else if (child == 0) {
662 return doit_conn (kc, sock, sock, flags, 1);
663 } else {
669 * Receive a connection on `sock' and process it.
672 static int
673 doit(int sock, int tcp_flag)
675 int ret;
676 kx_context context;
677 int dispnr;
678 int nsockets;
679 struct x_socket *sockets;
680 int flags;
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);
687 } else {
688 ret = doit_active (&context, sock, flags, tcp_flag);
689 cleanup(nsockets, sockets);
691 context_destroy (&context);
692 return ret;
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",
706 "port" },
707 { "version", 0, arg_flag, &version_flag },
708 { "help", 0, arg_flag, &help_flag }
711 static void
712 usage(int ret)
714 arg_printusage (args,
715 sizeof(args) / sizeof(args[0]),
716 NULL,
717 "host");
718 exit (ret);
722 * kxd - receive a forwarded X conncection
726 main (int argc, char **argv)
728 int port;
729 int optidx = 0;
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,
735 &optidx))
736 usage (1);
738 if (help_flag)
739 usage (0);
741 if (version_flag) {
742 print_version (NULL);
743 return 0;
746 if(port_str) {
747 struct servent *s = roken_getservbyname (port_str, "tcp");
749 if (s)
750 port = s->s_port;
751 else {
752 char *ptr;
754 port = strtol (port_str, &ptr, 10);
755 if (port == 0 && ptr == port_str)
756 errx (1, "bad port `%s'", port_str);
757 port = htons(port);
759 } else {
760 #if defined(KRB5)
761 port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT);
762 #elif defined(KRB4)
763 port = k_getportbyname ("kx", "tcp", htons(KX_PORT));
764 #else
765 #error define KRB4 or KRB5
766 #endif
769 if (!inetd_flag)
770 mini_inetd (port);
772 signal (SIGCHLD, childhandler);
773 return doit(STDIN_FILENO, tcp_flag);