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("$Heimdal: common.c 20452 2007-04-19 20:04:19Z lha $"
39 char x_socket
[MaxPathLen
];
42 char display
[MaxPathLen
];
43 int display_size
= sizeof(display
);
44 char xauthfile
[MaxPathLen
];
45 int xauthfile_size
= sizeof(xauthfile
);
47 size_t cookie_len
= sizeof(cookie
);
50 #define X_UNIX_PATH "/tmp/.X11-unix/X"
54 #define X_PIPE_PATH "/tmp/.X11-pipe/X"
58 * Allocate a unix domain socket in `s' for display `dpy' and with
62 * -1 if bind failed badly
63 * 1 if dpy is already used */
66 try_socket (struct x_socket
*s
, int dpy
, const char *pattern
)
68 struct sockaddr_un addr
;
71 fd
= socket (AF_UNIX
, SOCK_STREAM
, 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
);
78 (struct sockaddr
*)&addr
,
81 if (errno
== EADDRINUSE
||
82 errno
== EACCES
/* Cray return EACCESS */
84 || errno
== ENOTUNIQ
/* bug in Solaris 2.4 */
92 s
->pathname
= strdup (addr
.sun_path
);
93 if (s
->pathname
== NULL
)
94 errx (1, "strdup: out of memory");
95 s
->flags
= UNIX_SOCKET
;
99 #ifdef MAY_HAVE_X11_PIPES
101 * Allocate a stream (masqueraded as a named pipe)
104 * -1 if bind failed badly
105 * 1 if dpy is already used
109 try_pipe (struct x_socket
*s
, int dpy
, const char *pattern
)
111 char path
[MAXPATHLEN
];
116 snprintf (path
, sizeof(path
), pattern
, dpy
);
117 fd
= open (path
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
131 ret
= ioctl (pipefd
[1], I_PUSH
, "connld");
135 err (1, "ioctl I_PUSH");
138 ret
= fattach (pipefd
[1], path
);
140 err (1, "fattach %s", path
);
144 s
->pathname
= strdup (path
);
145 if (s
->pathname
== NULL
)
146 errx (1, "strdup: out of memory");
147 s
->flags
= STREAM_PIPE
;
150 #endif /* MAY_HAVE_X11_PIPES */
153 * Try to create a TCP socket in `s' corresponding to display `dpy'.
156 * -1 if bind failed badly
157 * 1 if dpy is already used
161 try_tcp (struct x_socket
*s
, int dpy
)
163 struct sockaddr_in tcpaddr
;
164 struct in_addr local
;
168 memset(&local
, 0, sizeof(local
));
169 local
.s_addr
= htonl(INADDR_LOOPBACK
);
171 fd
= socket (AF_INET
, SOCK_STREAM
, 0);
173 err (1, "socket AF_INET");
174 #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT)
175 setsockopt (fd
, IPPROTO_TCP
, TCP_NODELAY
, (void *)&one
,
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) {
185 if (errno
== EADDRINUSE
)
197 * The potential places to create unix sockets.
200 static char *x_sockets
[] = {
202 "/var/X/.X11-unix/X" "%u",
203 "/usr/spool/sockets/X11/" "%u",
208 * Dito for stream pipes.
211 #ifdef MAY_HAVE_X11_PIPES
212 static char *x_pipes
[] = {
214 "/var/X/.X11-pipe/X" "%u",
220 * Create the directory corresponding to dirname of `path' or fail.
224 try_mkdir (const char *path
)
230 if((dir
= strdup (path
)) == NULL
)
231 errx (1, "strdup: out of memory");
232 p
= strrchr (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
)
258 s
= malloc (sizeof(*s
) * 5);
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
) {
270 for (path
= x_sockets
; *path
; ++path
) {
271 tmp
= try_socket (&s
[n
], dpy
, *path
);
273 if (errno
!= ENOTDIR
&& errno
!= ENOENT
)
275 } else if (tmp
== 1) {
278 free (s
[n
].pathname
);
287 #ifdef MAY_HAVE_X11_PIPES
288 for (path
= x_pipes
; *path
; ++path
) {
289 tmp
= try_pipe (&s
[n
], dpy
, *path
);
291 if (errno
!= ENOTDIR
&& errno
!= ENOENT
&& errno
!= ENOSYS
)
293 } else if (tmp
== 1) {
296 free (s
[n
].pathname
);
308 tmp
= try_tcp (&s
[n
], dpy
);
314 free (s
[n
].pathname
);
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");
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
)
343 for (i
= 0; i
< n
; ++i
)
344 if (sockets
[i
].pathname
!= NULL
)
345 if (chown (sockets
[i
].pathname
, uid
, gid
) < 0)
351 * Connect to local display `dnr' with local transport or TCP.
352 * Return a file descriptor.
356 connect_local_xsocket (unsigned dnr
)
361 for (path
= x_sockets
; *path
; ++path
) {
362 struct sockaddr_un addr
;
364 fd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
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)
375 struct sockaddr_in addr
;
377 fd
= socket(AF_INET
, SOCK_STREAM
, 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)
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
,
408 char hostname
[MaxHostNameLen
];
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
);
419 auth
.name
= COOKIE_TYPE
;
420 auth
.name_length
= strlen(auth
.name
);
421 auth
.data_length
= cookie_sz
;
422 auth
.data
= (char*)cookie_buf
;
424 krb5_generate_random_block (cookie_buf
, cookie_sz
);
426 krb_generate_random_block (cookie_buf
, cookie_sz
);
429 strlcpy(file
, "/tmp/AXXXXXX", file_size
);
433 syslog(LOG_ERR
, "create_and_write_cookie: mkstemp: %m");
436 f
= fdopen(fd
, "r+");
442 if(XauWriteAuth(f
, &auth
) == 0) {
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) {
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.
475 * The protocol is as follows:
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
484 * authorization protocol name n
486 * authorization protocol data d
492 * protocol major version 2
493 * protocol minor version 2
494 * length in 4 bytes unit of
495 * additional data (n+p)/4 2
501 verify_and_remove_cookies (int fd
, int sock
, int cookiesp
)
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',
515 if (net_read (fd
, beg
, sizeof(beg
)) != sizeof(beg
))
517 if (net_write (sock
, beg
, 6) != 6)
519 bigendianp
= beg
[0] == 'B';
521 n
= (beg
[6] << 8) | beg
[7];
522 d
= (beg
[8] << 8) | beg
[9];
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
)
532 protocol_data
= malloc(d
+ dpad
);
533 if (d
+ dpad
!= 0 && protocol_data
== NULL
) {
534 free (protocol_name
);
537 if (net_read (fd
, protocol_name
, n
+ npad
) != n
+ npad
)
539 if (net_read (fd
, protocol_data
, d
+ dpad
) != d
+ dpad
)
542 if (strncmp (protocol_name
, COOKIE_TYPE
, strlen(COOKIE_TYPE
)) != 0)
544 if (d
!= cookie_len
||
545 memcmp (protocol_data
, cookie
, cookie_len
) != 0)
548 free (protocol_name
);
549 free (protocol_data
);
550 if (net_write (sock
, zeros
, 6) != 6)
563 net_write (fd
, refused
, sizeof(refused
));
565 free (protocol_name
);
566 free (protocol_data
);
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'.
577 match_local_auth (Xauth
* auth
,
578 struct addrinfo
*ai
, const char *hostname
, int disp_nr
)
584 tmp_disp
= malloc(auth
->number_length
+ 1);
585 if (tmp_disp
== NULL
)
587 memcpy(tmp_disp
, auth
->number
, auth
->number_length
);
588 tmp_disp
[auth
->number_length
] = '\0';
589 auth_disp
= atoi(tmp_disp
);
591 if (auth_disp
!= disp_nr
)
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
,
599 auth
->address_length
) == 0)
603 && (auth
->family
== FamilyLocal
604 || auth
->family
== FamilyWild
)
605 && strncmp (auth
->address
, hostname
, auth
->address_length
) == 0)
611 * Find `our' cookie from the cookie file `f' and return it or NULL.
615 find_auth_cookie (FILE *f
)
618 char local_hostname
[MaxHostNameLen
];
619 char *display_str
= getenv("DISPLAY");
620 char d
[MaxHostNameLen
+ 4];
623 struct addrinfo hints
;
627 if(display_str
== NULL
)
629 strlcpy(d
, display_str
, sizeof(d
));
631 colon
= strchr (display_str
, ':');
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
);
653 for (; (ret
= XauReadAuth (f
)) != NULL
; XauDisposeAuth(ret
)) {
654 if (match_local_auth (ret
, ai
, display_str
, disp
) == 0) {
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 */
675 unsigned n
, d
, npad
, dpad
;
677 u_char zeros
[6] = {0, 0, 0, 0, 0, 0};
679 if (net_read (fd
, beg
, sizeof(beg
)) != sizeof(beg
))
681 if (net_write (xserver
, beg
, 6) != 6)
683 bigendianp
= beg
[0] == 'B';
685 n
= (beg
[6] << 8) | beg
[7];
686 d
= (beg
[8] << 8) | beg
[9];
688 n
= (beg
[7] << 8) | beg
[6];
689 d
= (beg
[9] << 8) | beg
[8];
691 if (n
!= 0 || d
!= 0)
693 f
= fopen(filename
, "r");
695 Xauth
*auth
= find_auth_cookie (f
);
696 u_char len
[6] = {0, 0, 0, 0, 0, 0};
701 n
= auth
->name_length
;
702 d
= auth
->data_length
;
718 if (net_write (xserver
, len
, 6) != 6) {
719 XauDisposeAuth(auth
);
722 if(n
!= 0 && net_write (xserver
, auth
->name
, n
) != n
) {
723 XauDisposeAuth(auth
);
726 npad
= (4 - (n
% 4)) % 4;
727 if (npad
&& net_write (xserver
, zeros
, npad
) != npad
) {
728 XauDisposeAuth(auth
);
731 if (d
!= 0 && net_write (xserver
, auth
->data
, d
) != d
) {
732 XauDisposeAuth(auth
);
735 XauDisposeAuth(auth
);
736 dpad
= (4 - (d
% 4)) % 4;
737 if (dpad
&& net_write (xserver
, zeros
, dpad
) != dpad
)
740 if(net_write(xserver
, zeros
, 6) != 6)
747 * Some simple controls on the address and corresponding socket
751 suspicious_address (int sock
, struct sockaddr
*addr
)
754 socklen_t len
= sizeof(data
);
756 switch (addr
->sa_family
) {
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
768 /* XXX check route headers */
769 return !IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)addr
)->sin6_addr
);
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
784 kx_get_int(void *f
, uint32_t *to
, int size
, int lsb
)
787 unsigned char *from
= (unsigned char *)f
;
791 for(i
= size
-1; i
>= 0; i
--)
792 *to
= (*to
<< 8) | from
[i
];
794 for(i
= 0; i
< size
; i
++)
795 *to
= (*to
<< 8) | from
[i
];
801 kx_put_int(uint32_t from
, void *to
, size_t rem
, int size
)
804 unsigned char *p
= (unsigned char *)to
;
809 for(i
= size
- 1; i
>= 0; i
--){