No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / kx / common.c
blobab90d80b2a9c136fc885035e335a8749882121c3
1 /*
2 * Copyright (c) 1995 - 2001 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: common.c 20452 2007-04-19 20:04:19Z lha $"
37 "$NetBSD$");
39 char x_socket[MaxPathLen];
41 uint32_t display_num;
42 char display[MaxPathLen];
43 int display_size = sizeof(display);
44 char xauthfile[MaxPathLen];
45 int xauthfile_size = sizeof(xauthfile);
46 u_char cookie[16];
47 size_t cookie_len = sizeof(cookie);
49 #ifndef X_UNIX_PATH
50 #define X_UNIX_PATH "/tmp/.X11-unix/X"
51 #endif
53 #ifndef X_PIPE_PATH
54 #define X_PIPE_PATH "/tmp/.X11-pipe/X"
55 #endif
58 * Allocate a unix domain socket in `s' for display `dpy' and with
59 * filename `pattern'
61 * 0 if all is OK
62 * -1 if bind failed badly
63 * 1 if dpy is already used */
65 static int
66 try_socket (struct x_socket *s, int dpy, const char *pattern)
68 struct sockaddr_un addr;
69 int fd;
71 fd = socket (AF_UNIX, SOCK_STREAM, 0);
72 if (fd < 0)
73 err (1, "socket AF_UNIX");
74 memset (&addr, 0, sizeof(addr));
75 addr.sun_family = AF_UNIX;
76 snprintf (addr.sun_path, sizeof(addr.sun_path), pattern, dpy);
77 if(bind(fd,
78 (struct sockaddr *)&addr,
79 sizeof(addr)) < 0) {
80 close (fd);
81 if (errno == EADDRINUSE ||
82 errno == EACCES /* Cray return EACCESS */
83 #ifdef ENOTUNIQ
84 || errno == ENOTUNIQ /* bug in Solaris 2.4 */
85 #endif
87 return 1;
88 else
89 return -1;
91 s->fd = fd;
92 s->pathname = strdup (addr.sun_path);
93 if (s->pathname == NULL)
94 errx (1, "strdup: out of memory");
95 s->flags = UNIX_SOCKET;
96 return 0;
99 #ifdef MAY_HAVE_X11_PIPES
101 * Allocate a stream (masqueraded as a named pipe)
103 * 0 if all is OK
104 * -1 if bind failed badly
105 * 1 if dpy is already used
108 static int
109 try_pipe (struct x_socket *s, int dpy, const char *pattern)
111 char path[MAXPATHLEN];
112 int ret;
113 int fd;
114 int pipefd[2];
116 snprintf (path, sizeof(path), pattern, dpy);
117 fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600);
118 if (fd < 0) {
119 if (errno == EEXIST)
120 return 1;
121 else
122 return -1;
125 close (fd);
127 ret = pipe (pipefd);
128 if (ret < 0)
129 err (1, "pipe");
131 ret = ioctl (pipefd[1], I_PUSH, "connld");
132 if (ret < 0) {
133 if(errno == ENOSYS)
134 return -1;
135 err (1, "ioctl I_PUSH");
138 ret = fattach (pipefd[1], path);
139 if (ret < 0)
140 err (1, "fattach %s", path);
142 s->fd = pipefd[0];
143 close (pipefd[1]);
144 s->pathname = strdup (path);
145 if (s->pathname == NULL)
146 errx (1, "strdup: out of memory");
147 s->flags = STREAM_PIPE;
148 return 0;
150 #endif /* MAY_HAVE_X11_PIPES */
153 * Try to create a TCP socket in `s' corresponding to display `dpy'.
155 * 0 if all is OK
156 * -1 if bind failed badly
157 * 1 if dpy is already used
160 static int
161 try_tcp (struct x_socket *s, int dpy)
163 struct sockaddr_in tcpaddr;
164 struct in_addr local;
165 int one = 1;
166 int fd;
168 memset(&local, 0, sizeof(local));
169 local.s_addr = htonl(INADDR_LOOPBACK);
171 fd = socket (AF_INET, SOCK_STREAM, 0);
172 if (fd < 0)
173 err (1, "socket AF_INET");
174 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
175 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one,
176 sizeof(one));
177 #endif
178 memset (&tcpaddr, 0, sizeof(tcpaddr));
179 tcpaddr.sin_family = AF_INET;
180 tcpaddr.sin_addr = local;
181 tcpaddr.sin_port = htons(6000 + dpy);
182 if (bind (fd, (struct sockaddr *)&tcpaddr,
183 sizeof(tcpaddr)) < 0) {
184 close (fd);
185 if (errno == EADDRINUSE)
186 return 1;
187 else
188 return -1;
190 s->fd = fd;
191 s->pathname = NULL;
192 s->flags = TCP;
193 return 0;
197 * The potential places to create unix sockets.
200 static char *x_sockets[] = {
201 X_UNIX_PATH "%u",
202 "/var/X/.X11-unix/X" "%u",
203 "/usr/spool/sockets/X11/" "%u",
204 NULL
208 * Dito for stream pipes.
211 #ifdef MAY_HAVE_X11_PIPES
212 static char *x_pipes[] = {
213 X_PIPE_PATH "%u",
214 "/var/X/.X11-pipe/X" "%u",
215 NULL
217 #endif
220 * Create the directory corresponding to dirname of `path' or fail.
223 static void
224 try_mkdir (const char *path)
226 char *dir;
227 char *p;
228 int oldmask;
230 if((dir = strdup (path)) == NULL)
231 errx (1, "strdup: out of memory");
232 p = strrchr (dir, '/');
233 if (p)
234 *p = '\0';
236 oldmask = umask(0);
237 mkdir (dir, 01777);
238 umask (oldmask);
239 free (dir);
243 * Allocate a display, returning the number of sockets in `number' and
244 * all the corresponding sockets in `sockets'. If `tcp_socket' is
245 * true, also allcoaet a TCP socket.
247 * The return value is the display allocated or -1 if an error occurred.
251 get_xsockets (int *number, struct x_socket **sockets, int tcp_socket)
253 int dpy;
254 struct x_socket *s;
255 int n;
256 int i;
258 s = malloc (sizeof(*s) * 5);
259 if (s == NULL)
260 errx (1, "malloc: out of memory");
262 try_mkdir (X_UNIX_PATH);
263 try_mkdir (X_PIPE_PATH);
265 for(dpy = 4; dpy < 256; ++dpy) {
266 char **path;
267 int tmp = 0;
269 n = 0;
270 for (path = x_sockets; *path; ++path) {
271 tmp = try_socket (&s[n], dpy, *path);
272 if (tmp == -1) {
273 if (errno != ENOTDIR && errno != ENOENT)
274 return -1;
275 } else if (tmp == 1) {
276 while(--n >= 0) {
277 close (s[n].fd);
278 free (s[n].pathname);
280 break;
281 } else if (tmp == 0)
282 ++n;
284 if (tmp == 1)
285 continue;
287 #ifdef MAY_HAVE_X11_PIPES
288 for (path = x_pipes; *path; ++path) {
289 tmp = try_pipe (&s[n], dpy, *path);
290 if (tmp == -1) {
291 if (errno != ENOTDIR && errno != ENOENT && errno != ENOSYS)
292 return -1;
293 } else if (tmp == 1) {
294 while (--n >= 0) {
295 close (s[n].fd);
296 free (s[n].pathname);
298 break;
299 } else if (tmp == 0)
300 ++n;
303 if (tmp == 1)
304 continue;
305 #endif
307 if (tcp_socket) {
308 tmp = try_tcp (&s[n], dpy);
309 if (tmp == -1)
310 return -1;
311 else if (tmp == 1) {
312 while (--n >= 0) {
313 close (s[n].fd);
314 free (s[n].pathname);
316 break;
317 } else if (tmp == 0)
318 ++n;
320 break;
322 if (dpy == 256)
323 errx (1, "no free x-servers");
324 for (i = 0; i < n; ++i)
325 if (s[i].flags & LISTENP
326 && listen (s[i].fd, SOMAXCONN) < 0)
327 err (1, "listen %s", s[i].pathname ? s[i].pathname : "tcp");
328 *number = n;
329 *sockets = s;
330 return dpy;
334 * Change owner on the `n' sockets in `sockets' to `uid', `gid'.
335 * Return 0 is succesful or -1 if an error occurred.
339 chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid)
341 int i;
343 for (i = 0; i < n; ++i)
344 if (sockets[i].pathname != NULL)
345 if (chown (sockets[i].pathname, uid, gid) < 0)
346 return -1;
347 return 0;
351 * Connect to local display `dnr' with local transport or TCP.
352 * Return a file descriptor.
356 connect_local_xsocket (unsigned dnr)
358 int fd;
359 char **path;
361 for (path = x_sockets; *path; ++path) {
362 struct sockaddr_un addr;
364 fd = socket (AF_UNIX, SOCK_STREAM, 0);
365 if (fd < 0)
366 break;
367 memset (&addr, 0, sizeof(addr));
368 addr.sun_family = AF_UNIX;
369 snprintf (addr.sun_path, sizeof(addr.sun_path), *path, dnr);
370 if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
371 return fd;
372 close(fd);
375 struct sockaddr_in addr;
377 fd = socket(AF_INET, SOCK_STREAM, 0);
378 if (fd < 0)
379 err (1, "socket AF_INET");
380 memset (&addr, 0, sizeof(addr));
381 addr.sin_family = AF_INET;
382 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
383 addr.sin_port = htons(6000 + dnr);
384 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
385 return fd;
386 close(fd);
388 err (1, "connecting to local display %u", dnr);
392 * Create a cookie file with a random cookie for the localhost. The
393 * file name will be stored in `xauthfile' (but not larger than
394 * `xauthfile_size'), and the cookie returned in `cookie', `cookie_sz'.
395 * Return 0 if succesful, or errno.
399 create_and_write_cookie (char *file,
400 size_t file_size,
401 u_char *cookie_buf,
402 size_t cookie_sz)
404 Xauth auth;
405 char tmp[64];
406 int fd;
407 FILE *f;
408 char hostname[MaxHostNameLen];
409 int saved_errno;
411 gethostname (hostname, sizeof(hostname));
413 auth.family = FamilyLocal;
414 auth.address = hostname;
415 auth.address_length = strlen(auth.address);
416 snprintf (tmp, sizeof(tmp), "%d", display_num);
417 auth.number_length = strlen(tmp);
418 auth.number = tmp;
419 auth.name = COOKIE_TYPE;
420 auth.name_length = strlen(auth.name);
421 auth.data_length = cookie_sz;
422 auth.data = (char*)cookie_buf;
423 #ifdef KRB5
424 krb5_generate_random_block (cookie_buf, cookie_sz);
425 #else
426 krb_generate_random_block (cookie_buf, cookie_sz);
427 #endif
429 strlcpy(file, "/tmp/AXXXXXX", file_size);
430 fd = mkstemp(file);
431 if(fd < 0) {
432 saved_errno = errno;
433 syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m");
434 return saved_errno;
436 f = fdopen(fd, "r+");
437 if(f == NULL){
438 saved_errno = errno;
439 close(fd);
440 return errno;
442 if(XauWriteAuth(f, &auth) == 0) {
443 saved_errno = errno;
444 fclose(f);
445 return saved_errno;
449 * I would like to write a cookie for localhost:n here, but some
450 * stupid code in libX11 will not look for cookies of that type,
451 * so we are forced to use FamilyWild instead.
454 auth.family = FamilyWild;
455 auth.address_length = 0;
457 if (XauWriteAuth(f, &auth) == 0) {
458 saved_errno = errno;
459 fclose (f);
460 return saved_errno;
463 if(fclose(f))
464 return errno;
465 return 0;
469 * Verify and remove cookies. Read and parse a X-connection from
470 * `fd'. Check the cookie used is the same as in `cookie'. Remove the
471 * cookie and copy the rest of it to `sock'.
472 * Expect cookies iff cookiesp.
473 * Return 0 iff ok.
475 * The protocol is as follows:
477 * C->S: [Bl] 1
478 * unused 1
479 * protocol major version 2
480 * protocol minor version 2
481 * length of auth protocol name(n) 2
482 * length of auth protocol data 2
483 * unused 2
484 * authorization protocol name n
485 * pad pad(n)
486 * authorization protocol data d
487 * pad pad(d)
489 * S->C: Failed
490 * 0 1
491 * length of reason 1
492 * protocol major version 2
493 * protocol minor version 2
494 * length in 4 bytes unit of
495 * additional data (n+p)/4 2
496 * reason n
497 * unused p = pad(n)
501 verify_and_remove_cookies (int fd, int sock, int cookiesp)
503 u_char beg[12];
504 int bigendianp;
505 unsigned n, d, npad, dpad;
506 char *protocol_name, *protocol_data;
507 u_char zeros[6] = {0, 0, 0, 0, 0, 0};
508 u_char refused[20] = {0, 10,
509 0, 0, /* protocol major version */
510 0, 0, /* protocol minor version */
511 0, 0, /* length of additional data / 4 */
512 'b', 'a', 'd', ' ', 'c', 'o', 'o', 'k', 'i', 'e',
513 0, 0};
515 if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
516 return 1;
517 if (net_write (sock, beg, 6) != 6)
518 return 1;
519 bigendianp = beg[0] == 'B';
520 if (bigendianp) {
521 n = (beg[6] << 8) | beg[7];
522 d = (beg[8] << 8) | beg[9];
523 } else {
524 n = (beg[7] << 8) | beg[6];
525 d = (beg[9] << 8) | beg[8];
527 npad = (4 - (n % 4)) % 4;
528 dpad = (4 - (d % 4)) % 4;
529 protocol_name = malloc(n + npad);
530 if (n + npad != 0 && protocol_name == NULL)
531 return 1;
532 protocol_data = malloc(d + dpad);
533 if (d + dpad != 0 && protocol_data == NULL) {
534 free (protocol_name);
535 return 1;
537 if (net_read (fd, protocol_name, n + npad) != n + npad)
538 goto fail;
539 if (net_read (fd, protocol_data, d + dpad) != d + dpad)
540 goto fail;
541 if (cookiesp) {
542 if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0)
543 goto refused;
544 if (d != cookie_len ||
545 memcmp (protocol_data, cookie, cookie_len) != 0)
546 goto refused;
548 free (protocol_name);
549 free (protocol_data);
550 if (net_write (sock, zeros, 6) != 6)
551 return 1;
552 return 0;
553 refused:
554 refused[2] = beg[2];
555 refused[3] = beg[3];
556 refused[4] = beg[4];
557 refused[5] = beg[5];
558 if (bigendianp)
559 refused[7] = 3;
560 else
561 refused[6] = 3;
563 net_write (fd, refused, sizeof(refused));
564 fail:
565 free (protocol_name);
566 free (protocol_data);
567 return 1;
571 * Return 0 iff `cookie' is compatible with the cookie for the
572 * localhost with name given in `ai' (or `hostname') and display
573 * number in `disp_nr'.
576 static int
577 match_local_auth (Xauth* auth,
578 struct addrinfo *ai, const char *hostname, int disp_nr)
580 int auth_disp;
581 char *tmp_disp;
582 struct addrinfo *a;
584 tmp_disp = malloc(auth->number_length + 1);
585 if (tmp_disp == NULL)
586 return -1;
587 memcpy(tmp_disp, auth->number, auth->number_length);
588 tmp_disp[auth->number_length] = '\0';
589 auth_disp = atoi(tmp_disp);
590 free (tmp_disp);
591 if (auth_disp != disp_nr)
592 return 1;
593 for (a = ai; a != NULL; a = a->ai_next) {
594 if ((auth->family == FamilyLocal
595 || auth->family == FamilyWild)
596 && a->ai_canonname != NULL
597 && strncmp (auth->address,
598 a->ai_canonname,
599 auth->address_length) == 0)
600 return 0;
602 if (hostname != NULL
603 && (auth->family == FamilyLocal
604 || auth->family == FamilyWild)
605 && strncmp (auth->address, hostname, auth->address_length) == 0)
606 return 0;
607 return 1;
611 * Find `our' cookie from the cookie file `f' and return it or NULL.
614 static Xauth*
615 find_auth_cookie (FILE *f)
617 Xauth *ret = NULL;
618 char local_hostname[MaxHostNameLen];
619 char *display_str = getenv("DISPLAY");
620 char d[MaxHostNameLen + 4];
621 char *colon;
622 struct addrinfo *ai;
623 struct addrinfo hints;
624 int disp;
625 int error;
627 if(display_str == NULL)
628 display_str = ":0";
629 strlcpy(d, display_str, sizeof(d));
630 display_str = d;
631 colon = strchr (display_str, ':');
632 if (colon == NULL)
633 disp = 0;
634 else {
635 *colon = '\0';
636 disp = atoi (colon + 1);
638 if (strcmp (display_str, "") == 0
639 || strncmp (display_str, "unix", 4) == 0
640 || strncmp (display_str, "localhost", 9) == 0) {
641 gethostname (local_hostname, sizeof(local_hostname));
642 display_str = local_hostname;
644 memset (&hints, 0, sizeof(hints));
645 hints.ai_flags = AI_CANONNAME;
646 hints.ai_socktype = SOCK_STREAM;
647 hints.ai_protocol = IPPROTO_TCP;
649 error = getaddrinfo (display_str, NULL, &hints, &ai);
650 if (error)
651 ai = NULL;
653 for (; (ret = XauReadAuth (f)) != NULL; XauDisposeAuth(ret)) {
654 if (match_local_auth (ret, ai, display_str, disp) == 0) {
655 if (ai != NULL)
656 freeaddrinfo (ai);
657 return ret;
660 if (ai != NULL)
661 freeaddrinfo (ai);
662 return NULL;
666 * Get rid of the cookie that we were sent and get the correct one
667 * from our own cookie file instead.
671 replace_cookie(int xserver, int fd, char *filename, int cookiesp) /* XXX */
673 u_char beg[12];
674 int bigendianp;
675 unsigned n, d, npad, dpad;
676 FILE *f;
677 u_char zeros[6] = {0, 0, 0, 0, 0, 0};
679 if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
680 return 1;
681 if (net_write (xserver, beg, 6) != 6)
682 return 1;
683 bigendianp = beg[0] == 'B';
684 if (bigendianp) {
685 n = (beg[6] << 8) | beg[7];
686 d = (beg[8] << 8) | beg[9];
687 } else {
688 n = (beg[7] << 8) | beg[6];
689 d = (beg[9] << 8) | beg[8];
691 if (n != 0 || d != 0)
692 return 1;
693 f = fopen(filename, "r");
694 if (f != NULL) {
695 Xauth *auth = find_auth_cookie (f);
696 u_char len[6] = {0, 0, 0, 0, 0, 0};
698 fclose (f);
700 if (auth != NULL) {
701 n = auth->name_length;
702 d = auth->data_length;
703 } else {
704 n = 0;
705 d = 0;
707 if (bigendianp) {
708 len[0] = n >> 8;
709 len[1] = n & 0xFF;
710 len[2] = d >> 8;
711 len[3] = d & 0xFF;
712 } else {
713 len[0] = n & 0xFF;
714 len[1] = n >> 8;
715 len[2] = d & 0xFF;
716 len[3] = d >> 8;
718 if (net_write (xserver, len, 6) != 6) {
719 XauDisposeAuth(auth);
720 return 1;
722 if(n != 0 && net_write (xserver, auth->name, n) != n) {
723 XauDisposeAuth(auth);
724 return 1;
726 npad = (4 - (n % 4)) % 4;
727 if (npad && net_write (xserver, zeros, npad) != npad) {
728 XauDisposeAuth(auth);
729 return 1;
731 if (d != 0 && net_write (xserver, auth->data, d) != d) {
732 XauDisposeAuth(auth);
733 return 1;
735 XauDisposeAuth(auth);
736 dpad = (4 - (d % 4)) % 4;
737 if (dpad && net_write (xserver, zeros, dpad) != dpad)
738 return 1;
739 } else {
740 if(net_write(xserver, zeros, 6) != 6)
741 return 1;
743 return 0;
747 * Some simple controls on the address and corresponding socket
751 suspicious_address (int sock, struct sockaddr *addr)
753 char data[40];
754 socklen_t len = sizeof(data);
756 switch (addr->sa_family) {
757 case AF_INET:
758 return ((struct sockaddr_in *)addr)->sin_addr.s_addr !=
759 htonl(INADDR_LOOPBACK)
760 #if defined(IP_OPTIONS) && defined(HAVE_GETSOCKOPT)
761 || getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0
762 || len != 0
763 #endif
765 break;
766 #ifdef HAVE_IPV6
767 case AF_INET6:
768 /* XXX check route headers */
769 return !IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)addr)->sin6_addr);
770 #endif
771 default:
772 return 1;
777 * This really sucks, but these functions are used and if we're not
778 * linking against libkrb they don't exist. Using the heimdal storage
779 * functions will not work either cause we do not always link with
780 * libkrb5 either.
784 kx_get_int(void *f, uint32_t *to, int size, int lsb)
786 int i;
787 unsigned char *from = (unsigned char *)f;
789 *to = 0;
790 if(lsb){
791 for(i = size-1; i >= 0; i--)
792 *to = (*to << 8) | from[i];
793 }else{
794 for(i = 0; i < size; i++)
795 *to = (*to << 8) | from[i];
797 return size;
801 kx_put_int(uint32_t from, void *to, size_t rem, int size)
803 int i;
804 unsigned char *p = (unsigned char *)to;
806 if (rem < size)
807 return -1;
809 for(i = size - 1; i >= 0; i--){
810 p[i] = from & 0xff;
811 from >>= 8;
813 return size;