2 * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
36 RCSID("$Id: common.c,v 1.68 2003/04/16 16:45:39 joda Exp $");
38 char x_socket[MaxPathLen];
40 u_int32_t display_num;
41 char display[MaxPathLen];
42 int display_size = sizeof(display);
43 char xauthfile[MaxPathLen];
44 int xauthfile_size = sizeof(xauthfile);
46 size_t cookie_len = sizeof(cookie);
49 #define X_UNIX_PATH "/tmp/.X11-unix/X"
53 #define X_PIPE_PATH "/tmp/.X11-pipe/X"
57 * Allocate a unix domain socket in `s' for display `dpy' and with
61 * -1 if bind failed badly
62 * 1 if dpy is already used */
65 try_socket (struct x_socket *s, int dpy, const char *pattern)
67 struct sockaddr_un addr;
70 fd = socket (AF_UNIX, SOCK_STREAM, 0);
72 err (1, "socket AF_UNIX");
73 memset (&addr, 0, sizeof(addr));
74 addr.sun_family = AF_UNIX;
75 snprintf (addr.sun_path, sizeof(addr.sun_path), pattern, dpy);
77 (struct sockaddr *)&addr,
80 if (errno == EADDRINUSE ||
81 errno == EACCES /* Cray return EACCESS */
83 || errno == ENOTUNIQ /* bug in Solaris 2.4 */
91 s->pathname = strdup (addr.sun_path);
92 if (s->pathname == NULL)
93 errx (1, "strdup: out of memory");
94 s->flags = UNIX_SOCKET;
98 #ifdef MAY_HAVE_X11_PIPES
100 * Allocate a stream (masqueraded as a named pipe)
103 * -1 if bind failed badly
104 * 1 if dpy is already used
108 try_pipe (struct x_socket *s, int dpy, const char *pattern)
110 char path[MAXPATHLEN];
115 snprintf (path, sizeof(path), pattern, dpy);
116 fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600);
130 ret = ioctl (pipefd[1], I_PUSH, "connld");
134 err (1, "ioctl I_PUSH");
137 ret = fattach (pipefd[1], path);
139 err (1, "fattach %s", path);
143 s->pathname = strdup (path);
144 if (s->pathname == NULL)
145 errx (1, "strdup: out of memory");
146 s->flags = STREAM_PIPE;
149 #endif /* MAY_HAVE_X11_PIPES */
152 * Try to create a TCP socket in `s' corresponding to display `dpy'.
155 * -1 if bind failed badly
156 * 1 if dpy is already used
160 try_tcp (struct x_socket *s, int dpy)
162 struct sockaddr_in tcpaddr;
163 struct in_addr local;
167 memset(&local, 0, sizeof(local));
168 local.s_addr = htonl(INADDR_LOOPBACK);
170 fd = socket (AF_INET, SOCK_STREAM, 0);
172 err (1, "socket AF_INET");
173 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
174 setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one,
177 memset (&tcpaddr, 0, sizeof(tcpaddr));
178 tcpaddr.sin_family = AF_INET;
179 tcpaddr.sin_addr = local;
180 tcpaddr.sin_port = htons(6000 + dpy);
181 if (bind (fd, (struct sockaddr *)&tcpaddr,
182 sizeof(tcpaddr)) < 0) {
184 if (errno == EADDRINUSE)
196 * The potential places to create unix sockets.
199 static char *x_sockets[] = {
201 "/var/X/.X11-unix/X" "%u",
202 "/usr/spool/sockets/X11/" "%u",
207 * Dito for stream pipes.
210 #ifdef MAY_HAVE_X11_PIPES
211 static char *x_pipes[] = {
213 "/var/X/.X11-pipe/X" "%u",
219 * Create the directory corresponding to dirname of `path' or fail.
223 try_mkdir (const char *path)
229 if((dir = strdup (path)) == NULL)
230 errx (1, "strdup: out of memory");
231 p = strrchr (dir, '/');
242 * Allocate a display, returning the number of sockets in `number' and
243 * all the corresponding sockets in `sockets'. If `tcp_socket' is
244 * true, also allcoaet a TCP socket.
246 * The return value is the display allocated or -1 if an error occurred.
250 get_xsockets (int *number, struct x_socket **sockets, int tcp_socket)
257 s = malloc (sizeof(*s) * 5);
259 errx (1, "malloc: out of memory");
261 try_mkdir (X_UNIX_PATH);
262 try_mkdir (X_PIPE_PATH);
264 for(dpy = 4; dpy < 256; ++dpy) {
269 for (path = x_sockets; *path; ++path) {
270 tmp = try_socket (&s[n], dpy, *path);
272 if (errno != ENOTDIR && errno != ENOENT)
274 } else if (tmp == 1) {
277 free (s[n].pathname);
286 #ifdef MAY_HAVE_X11_PIPES
287 for (path = x_pipes; *path; ++path) {
288 tmp = try_pipe (&s[n], dpy, *path);
290 if (errno != ENOTDIR && errno != ENOENT && errno != ENOSYS)
292 } else if (tmp == 1) {
295 free (s[n].pathname);
307 tmp = try_tcp (&s[n], dpy);
313 free (s[n].pathname);
322 errx (1, "no free x-servers");
323 for (i = 0; i < n; ++i)
324 if (s[i].flags & LISTENP
325 && listen (s[i].fd, SOMAXCONN) < 0)
326 err (1, "listen %s", s[i].pathname ? s[i].pathname : "tcp");
333 * Change owner on the `n' sockets in `sockets' to `uid', `gid'.
334 * Return 0 is succesful or -1 if an error occurred.
338 chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid)
342 for (i = 0; i < n; ++i)
343 if (sockets[i].pathname != NULL)
344 if (chown (sockets[i].pathname, uid, gid) < 0)
350 * Connect to local display `dnr' with local transport or TCP.
351 * Return a file descriptor.
355 connect_local_xsocket (unsigned dnr)
360 for (path = x_sockets; *path; ++path) {
361 struct sockaddr_un addr;
363 fd = socket (AF_UNIX, SOCK_STREAM, 0);
366 memset (&addr, 0, sizeof(addr));
367 addr.sun_family = AF_UNIX;
368 snprintf (addr.sun_path, sizeof(addr.sun_path), *path, dnr);
369 if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
374 struct sockaddr_in addr;
376 fd = socket(AF_INET, SOCK_STREAM, 0);
378 err (1, "socket AF_INET");
379 memset (&addr, 0, sizeof(addr));
380 addr.sin_family = AF_INET;
381 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
382 addr.sin_port = htons(6000 + dnr);
383 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
387 err (1, "connecting to local display %u", dnr);
391 * Create a cookie file with a random cookie for the localhost. The
392 * file name will be stored in `xauthfile' (but not larger than
393 * `xauthfile_size'), and the cookie returned in `cookie', `cookie_sz'.
394 * Return 0 if succesful, or errno.
398 create_and_write_cookie (char *xauthfile,
399 size_t xauthfile_size,
407 char hostname[MaxHostNameLen];
410 gethostname (hostname, sizeof(hostname));
412 auth.family = FamilyLocal;
413 auth.address = hostname;
414 auth.address_length = strlen(auth.address);
415 snprintf (tmp, sizeof(tmp), "%d", display_num);
416 auth.number_length = strlen(tmp);
418 auth.name = COOKIE_TYPE;
419 auth.name_length = strlen(auth.name);
420 auth.data_length = cookie_sz;
421 auth.data = (char*)cookie;
423 krb5_generate_random_block (cookie, cookie_sz);
425 krb_generate_random_block (cookie, cookie_sz);
428 strlcpy(xauthfile, "/tmp/AXXXXXX", xauthfile_size);
429 fd = mkstemp(xauthfile);
432 syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m");
435 f = fdopen(fd, "r+");
441 if(XauWriteAuth(f, &auth) == 0) {
448 * I would like to write a cookie for localhost:n here, but some
449 * stupid code in libX11 will not look for cookies of that type,
450 * so we are forced to use FamilyWild instead.
453 auth.family = FamilyWild;
454 auth.address_length = 0;
456 if (XauWriteAuth(f, &auth) == 0) {
468 * Verify and remove cookies. Read and parse a X-connection from
469 * `fd'. Check the cookie used is the same as in `cookie'. Remove the
470 * cookie and copy the rest of it to `sock'.
471 * Expect cookies iff cookiesp.
474 * The protocol is as follows:
478 * protocol major version 2
479 * protocol minor version 2
480 * length of auth protocol name(n) 2
481 * length of auth protocol data 2
483 * authorization protocol name n
485 * authorization protocol data d
491 * protocol major version 2
492 * protocol minor version 2
493 * length in 4 bytes unit of
494 * additional data (n+p)/4 2
500 verify_and_remove_cookies (int fd, int sock, int cookiesp)
504 unsigned n, d, npad, dpad;
505 char *protocol_name, *protocol_data;
506 u_char zeros[6] = {0, 0, 0, 0, 0, 0};
507 u_char refused[20] = {0, 10,
508 0, 0, /* protocol major version */
509 0, 0, /* protocol minor version */
510 0, 0, /* length of additional data / 4 */
511 'b', 'a', 'd', ' ', 'c', 'o', 'o', 'k', 'i', 'e',
514 if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
516 if (net_write (sock, beg, 6) != 6)
518 bigendianp = beg[0] == 'B';
520 n = (beg[6] << 8) | beg[7];
521 d = (beg[8] << 8) | beg[9];
523 n = (beg[7] << 8) | beg[6];
524 d = (beg[9] << 8) | beg[8];
526 npad = (4 - (n % 4)) % 4;
527 dpad = (4 - (d % 4)) % 4;
528 protocol_name = malloc(n + npad);
529 if (n + npad != 0 && protocol_name == NULL)
531 protocol_data = malloc(d + dpad);
532 if (d + dpad != 0 && protocol_data == NULL) {
533 free (protocol_name);
536 if (net_read (fd, protocol_name, n + npad) != n + npad)
538 if (net_read (fd, protocol_data, d + dpad) != d + dpad)
541 if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0)
543 if (d != cookie_len ||
544 memcmp (protocol_data, cookie, cookie_len) != 0)
547 free (protocol_name);
548 free (protocol_data);
549 if (net_write (sock, zeros, 6) != 6)
562 net_write (fd, refused, sizeof(refused));
564 free (protocol_name);
565 free (protocol_data);
570 * Return 0 iff `cookie' is compatible with the cookie for the
571 * localhost with name given in `ai' (or `hostname') and display
572 * number in `disp_nr'.
576 match_local_auth (Xauth* auth,
577 struct addrinfo *ai, const char *hostname, int disp_nr)
583 tmp_disp = malloc(auth->number_length + 1);
584 if (tmp_disp == NULL)
586 memcpy(tmp_disp, auth->number, auth->number_length);
587 tmp_disp[auth->number_length] = '\0';
588 auth_disp = atoi(tmp_disp);
590 if (auth_disp != disp_nr)
592 for (a = ai; a != NULL; a = a->ai_next) {
593 if ((auth->family == FamilyLocal
594 || auth->family == FamilyWild)
595 && a->ai_canonname != NULL
596 && strncmp (auth->address,
598 auth->address_length) == 0)
602 && (auth->family == FamilyLocal
603 || auth->family == FamilyWild)
604 && strncmp (auth->address, hostname, auth->address_length) == 0)
610 * Find `our' cookie from the cookie file `f' and return it or NULL.
614 find_auth_cookie (FILE *f)
617 char local_hostname[MaxHostNameLen];
618 char *display = getenv("DISPLAY");
619 char d[MaxHostNameLen + 4];
622 struct addrinfo hints;
628 strlcpy(d, display, sizeof(d));
630 colon = strchr (display, ':');
635 disp = atoi (colon + 1);
637 if (strcmp (display, "") == 0
638 || strncmp (display, "unix", 4) == 0
639 || strncmp (display, "localhost", 9) == 0) {
640 gethostname (local_hostname, sizeof(local_hostname));
641 display = local_hostname;
643 memset (&hints, 0, sizeof(hints));
644 hints.ai_flags = AI_CANONNAME;
645 hints.ai_socktype = SOCK_STREAM;
646 hints.ai_protocol = IPPROTO_TCP;
648 error = getaddrinfo (display, NULL, &hints, &ai);
652 for (; (ret = XauReadAuth (f)) != NULL; XauDisposeAuth(ret)) {
653 if (match_local_auth (ret, ai, display, disp) == 0) {
665 * Get rid of the cookie that we were sent and get the correct one
666 * from our own cookie file instead.
670 replace_cookie(int xserver, int fd, char *filename, int cookiesp) /* XXX */
674 unsigned n, d, npad, dpad;
676 u_char zeros[6] = {0, 0, 0, 0, 0, 0};
678 if (net_read (fd, beg, sizeof(beg)) != sizeof(beg))
680 if (net_write (xserver, beg, 6) != 6)
682 bigendianp = beg[0] == 'B';
684 n = (beg[6] << 8) | beg[7];
685 d = (beg[8] << 8) | beg[9];
687 n = (beg[7] << 8) | beg[6];
688 d = (beg[9] << 8) | beg[8];
690 if (n != 0 || d != 0)
692 f = fopen(filename, "r");
694 Xauth *auth = find_auth_cookie (f);
695 u_char len[6] = {0, 0, 0, 0, 0, 0};
700 n = auth->name_length;
701 d = auth->data_length;
717 if (net_write (xserver, len, 6) != 6) {
718 XauDisposeAuth(auth);
721 if(n != 0 && net_write (xserver, auth->name, n) != n) {
722 XauDisposeAuth(auth);
725 npad = (4 - (n % 4)) % 4;
726 if (npad && net_write (xserver, zeros, npad) != npad) {
727 XauDisposeAuth(auth);
730 if (d != 0 && net_write (xserver, auth->data, d) != d) {
731 XauDisposeAuth(auth);
734 XauDisposeAuth(auth);
735 dpad = (4 - (d % 4)) % 4;
736 if (dpad && net_write (xserver, zeros, dpad) != dpad)
739 if(net_write(xserver, zeros, 6) != 6)
746 * Some simple controls on the address and corresponding socket
750 suspicious_address (int sock, struct sockaddr *addr)
753 socklen_t len = sizeof(data);
755 switch (addr->sa_family) {
757 return ((struct sockaddr_in *)addr)->sin_addr.s_addr !=
758 htonl(INADDR_LOOPBACK)
759 #if defined(IP_OPTIONS) && defined(HAVE_GETSOCKOPT)
760 || getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0
767 /* XXX check route headers */
768 return !IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)addr)->sin6_addr);
776 * This really sucks, but these functions are used and if we're not
777 * linking against libkrb they don't exist. Using the heimdal storage
778 * functions will not work either cause we do not always link with
785 krb_get_int(void *f, u_int32_t *to, int size, int lsb)
788 unsigned char *from = (unsigned char *)f;
792 for(i = size-1; i >= 0; i--)
793 *to = (*to << 8) | from[i];
795 for(i = 0; i < size; i++)
796 *to = (*to << 8) | from[i];
802 krb_put_int(u_int32_t from, void *to, size_t rem, int size)
805 unsigned char *p = (unsigned char *)to;
810 for(i = size - 1; i >= 0; i--){