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
38 char x_socket
[MaxPathLen
];
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 *file
,
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_buf
;
423 krb5_generate_random_block (cookie_buf
, cookie_sz
);
425 krb_generate_random_block (cookie_buf
, cookie_sz
);
428 strlcpy(file
, "/tmp/AXXXXXX", file_size
);
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_str
= getenv("DISPLAY");
619 char d
[MaxHostNameLen
+ 4];
622 struct addrinfo hints
;
626 if(display_str
== NULL
)
628 strlcpy(d
, display_str
, sizeof(d
));
630 colon
= strchr (display_str
, ':');
635 disp
= atoi (colon
+ 1);
637 if (strcmp (display_str
, "") == 0
638 || strncmp (display_str
, "unix", 4) == 0
639 || strncmp (display_str
, "localhost", 9) == 0) {
640 gethostname (local_hostname
, sizeof(local_hostname
));
641 display_str
= 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_str
, NULL
, &hints
, &ai
);
652 for (; (ret
= XauReadAuth (f
)) != NULL
; XauDisposeAuth(ret
)) {
653 if (match_local_auth (ret
, ai
, display_str
, 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
783 kx_get_int(void *f
, uint32_t *to
, int size
, int lsb
)
786 unsigned char *from
= (unsigned char *)f
;
790 for(i
= size
-1; i
>= 0; i
--)
791 *to
= (*to
<< 8) | from
[i
];
793 for(i
= 0; i
< size
; i
++)
794 *to
= (*to
<< 8) | from
[i
];
800 kx_put_int(uint32_t from
, void *to
, size_t rem
, int size
)
803 unsigned char *p
= (unsigned char *)to
;
808 for(i
= size
- 1; i
>= 0; i
--){