remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / kx / kxd.c
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.
12  * 
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.
16  * 
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.
20  * 
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.
32  */
33
34 #include "kx.h"
35
36 RCSID("$Id: kxd.c,v 1.71.2.2 2003/05/15 15:11:35 lha Exp $");
37
38 static pid_t wait_on_pid = -1;
39 static int   done        = 0;
40
41 /*
42  * Signal handler that justs waits for the children when they die.
43  */
44
45 static RETSIGTYPE
46 childhandler (int sig)
47 {
48      pid_t pid;
49      int status;
50
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);
58 }
59
60 /*
61  * Print the error message `format' and `...' on fd and die.
62  */
63
64 void
65 fatal (kx_context *kc, int fd, char *format, ...)
66 {
67     u_char msg[1024];
68     u_char *p;
69     va_list args;
70     int len;
71
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);
83 }
84
85 /*
86  * Remove all sockets and cookie files.
87  */
88
89 static void
90 cleanup(int nsockets, struct x_socket *sockets)
91 {
92     int i;
93
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);
100         }
101     }
102 }
103
104 /*
105  * Prepare to receive a connection on `sock'.
106  */
107
108 static int
109 recv_conn (int sock, kx_context *kc,
110            int *dispnr, int *nsockets, struct x_socket **sockets,
111            int tcp_flag)
112 {
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;
123
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);
129      }
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);
136      }
137      kc->thataddr_len = addrlen;
138
139      getnameinfo_verified (kc->thataddr, 
140                            kc->thataddr_len,
141                            remotehost, sizeof(remotehost),
142                            NULL, 0, 0);
143
144      if (net_read (sock, msg, 4) != 4) {
145          syslog (LOG_ERR, "read: %m");
146          exit (1);
147      }
148
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);
161      }
162
163      len = kx_read (kc, sock, msg, sizeof(msg));
164      if (len < 0) {
165          syslog (LOG_ERR, "kx_read failed");
166          exit (1);
167      }
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';
177
178      passwd = k_getpwnam (user);
179      if (passwd == NULL)
180          fatal (kc, sock, "cannot find uid for %s", user);
181
182      if (context_userok (kc, user) != 0)
183          fatal (kc, sock, "%s not allowed to login as %s",
184                 kc->user, user);
185
186      flags = *p++;
187
188      if (flags & PASSIVE) {
189          pid_t pid;
190          int tmp;
191
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));
196          }
197          *dispnr = tmp;
198
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));
204          }
205
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);
216          }
217      }
218
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");
227      }
228
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));
234
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;
250      }
251 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
252      if (flags & KEEP_ALIVE) {
253          int one = 1;
254
255          setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
256                      sizeof(one));
257      }
258 #endif
259      return flags;
260 }
261
262 /*
263  *
264  */
265
266 static int
267 passive_session (kx_context *kc, int fd, int sock, int cookiesp)
268 {
269     if (verify_and_remove_cookies (fd, sock, cookiesp))
270         return 1;
271     else
272         return copy_encrypted (kc, fd, sock);
273 }
274
275 /*
276  *
277  */
278
279 static int
280 active_session (kx_context *kc, int fd, int sock, int cookiesp)
281 {
282     fd = connect_local_xsocket(0);
283
284     if (replace_cookie (fd, sock, xauthfile, cookiesp))
285         return 1;
286     else
287         return copy_encrypted (kc, fd, sock);
288 }
289
290 /*
291  * Handle a new connection.
292  */
293
294 static int
295 doit_conn (kx_context *kc,
296            int fd, int meta_sock, int flags, int cookiesp)
297 {
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;
305
306     sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0);
307     if (sock < 0) {
308         syslog (LOG_ERR, "socket: %m");
309         return 1;
310     }
311 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
312     {
313         int one = 1;
314         setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));
315     }
316 #endif
317 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
318     if (flags & KEEP_ALIVE) {
319         int one = 1;
320
321         setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
322                     sizeof(one));
323     }
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;
330     }
331     if (bind (sock, addr, kc->thisaddr_len) < 0) {
332         syslog (LOG_ERR, "bind: %m");
333         return 1;
334     }
335     addrlen = sizeof(__ss_addr);
336     if (getsockname (sock, addr, &addrlen) < 0) {
337         syslog (LOG_ERR, "getsockname: %m");
338         return 1;
339     }
340     if (listen (sock, SOMAXCONN) < 0) {
341         syslog (LOG_ERR, "listen: %m");
342         return 1;
343     }
344     port = socket_get_port(addr);
345
346     p = msg;
347     *p++ = NEW_CONN;
348     p += KRB_PUT_INT (ntohs(port), p, 4, 4);
349
350     if (kx_write (kc, meta_sock, msg, p - msg) < 0) {
351         syslog (LOG_ERR, "write: %m");
352         return 1;
353     }
354
355     addrlen = sizeof(__ss_thisaddr);
356     sock2 = accept (sock, thisaddr, &addrlen);
357     if (sock2 < 0) {
358         syslog (LOG_ERR, "accept: %m");
359         return 1;
360     }
361     close (sock);
362     close (meta_sock);
363
364     if (flags & PASSIVE)
365         return passive_session (kc, fd, sock2, cookiesp);
366     else
367         return active_session (kc, fd, sock2, cookiesp);
368 }
369
370 /*
371  *  Is the current user the owner of the console?
372  */
373
374 static void
375 check_user_console (kx_context *kc, int fd)
376 {
377      struct stat sb;
378
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");
383 }
384
385 /* close down the new connection with a reasonable error message */
386 static void
387 close_connection(int fd, const char *message)
388 {
389     char buf[264]; /* max message */
390     char *p;
391     int lsb = 0;
392     size_t mlen;
393
394     mlen = strlen(message);
395     if(mlen > 255)
396         mlen = 255;
397     
398     /* read first part of connection packet, to get byte order */
399     if(read(fd, buf, 6) != 6) {
400         close(fd);
401         return;
402     }
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;
414         
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;
422     }
423     write(fd, buf, p - buf);
424     close(fd);
425 }
426
427
428 /*
429  * Handle a passive session on `sock'
430  */
431
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)
440 {
441     int tmp;
442     int len;
443     size_t rem;
444     u_char msg[1024], *p;
445     int error;
446
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;
458     }
459
460     p = msg;
461     rem = sizeof(msg);
462     *p++ = ACK;
463     --rem;
464
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;
471     }
472     p += tmp;
473     rem -= tmp;
474
475     memcpy (p, display, len);
476     p += len;
477     rem -= len;
478
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;
485     }
486     p += tmp;
487     rem -= tmp;
488
489     memcpy (p, xauthfile, len);
490     p += len;
491     rem -= len;
492           
493     if(kx_write (kc, sock, msg, p - msg) < 0) {
494         syslog (LOG_ERR, "write: %m");
495         cleanup(nsockets, sockets);
496         return 1;
497     }
498     for (;;) {
499         pid_t child;
500         int fd = -1;
501         fd_set fds;
502         int i;
503         int ret;
504         int cookiesp = TRUE;
505                
506         FD_ZERO(&fds);
507         if (sock >= FD_SETSIZE) {
508             syslog (LOG_ERR, "fd too large");
509             cleanup(nsockets, sockets);
510             return 1;
511         }
512
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;
519             }
520             FD_SET(sockets[i].fd, &fds);
521         }
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
527              */
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);
537
538                         fd = accept (sockets[i].fd,
539                                      peer,
540                                      &len);
541                         if (fd < 0 && errno != EINTR)
542                             syslog (LOG_ERR, "accept: %m");
543
544                         /* XXX */
545                         if (fd >= 0 && suspicious_address (fd, peer)) {
546                             close (fd);
547                             fd = -1;
548                             errno = EINTR;
549                         }
550                     } else if(sockets[i].flags == UNIX_SOCKET) {
551                         socklen_t zero = 0;
552
553                         fd = accept (sockets[i].fd, NULL, &zero);
554
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) {
559                         /*
560                          * this code tries to handle the
561                          * send fd-over-pipe stuff for
562                          * solaris
563                          */
564
565                         struct strrecvfd strrecvfd;
566
567                         ret = ioctl (sockets[i].fd,
568                                      I_RECVFD, &strrecvfd);
569                         if (ret < 0 && errno != EINTR) {
570                             syslog (LOG_ERR, "ioctl I_RECVFD: %m");
571                         }
572
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;
582                             }
583                         }
584 #endif /* MAY_HAVE_X11_PIPES */
585                     } else
586                         abort ();
587                     break;
588                 }
589             }
590         }
591         if (fd < 0) {
592             if (errno == EINTR)
593                 continue;
594             else
595                 return 1;
596         }
597
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);
610         }
611     }
612 }
613
614 /*
615  * Handle an active session on `sock'
616  */
617
618 static int
619 doit_active (kx_context *kc,
620              int sock,
621              int flags,
622              int tcp_flag)
623 {
624     u_char msg[1024], *p;
625
626     check_user_console (kc, sock);
627
628     p = msg;
629     *p++ = ACK;
630           
631     if(kx_write (kc, sock, msg, p - msg) < 0) {
632         syslog (LOG_ERR, "write: %m");
633         return 1;
634     }
635     for (;;) {
636         pid_t child;
637         int len;
638               
639         len = kx_read (kc, sock, msg, sizeof(msg));
640         if (len < 0) {
641             syslog (LOG_ERR, "read: %m");
642             return 1;
643         }
644         p = (u_char *)msg;
645         if (*p != NEW_CONN) {
646             syslog (LOG_ERR, "bad_message: %d", *p);
647             return 1;
648         }
649
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 {
658         }
659     }
660 }
661
662 /*
663  * Receive a connection on `sock' and process it.
664  */
665
666 static int
667 doit(int sock, int tcp_flag)
668 {
669     int ret;
670     kx_context context;
671     int dispnr;
672     int nsockets;
673     struct x_socket *sockets;
674     int flags;
675
676     flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
677
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;
685 }
686
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;
692
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 }
701 };
702
703 static void
704 usage(int ret)
705 {
706     arg_printusage (args,
707                     sizeof(args) / sizeof(args[0]),
708                     NULL,
709                     "host");
710     exit (ret);
711 }
712
713 /*
714  * kxd - receive a forwarded X conncection
715  */
716
717 int
718 main (int argc, char **argv)
719 {
720     int port;
721     int optind = 0;
722
723     setprogname (argv[0]);
724     roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
725
726     if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
727                 &optind))
728         usage (1);
729
730     if (help_flag)
731         usage (0);
732
733     if (version_flag) {
734         print_version (NULL);
735         return 0;
736     }
737
738     if(port_str) {
739         struct servent *s = roken_getservbyname (port_str, "tcp");
740
741         if (s)
742             port = s->s_port;
743         else {
744             char *ptr;
745
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);
750         }
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
759     }
760
761     if (!inetd_flag)
762         mini_inetd (port);
763
764      signal (SIGCHLD, childhandler);
765      return doit(STDIN_FILENO, tcp_flag);
766 }