diff options
Diffstat (limited to 'libxcb')
-rw-r--r-- | libxcb/src/xcb_auth.c | 77 | ||||
-rw-r--r-- | libxcb/src/xcb_util.c | 31 |
2 files changed, 89 insertions, 19 deletions
diff --git a/libxcb/src/xcb_auth.c b/libxcb/src/xcb_auth.c index 104f2f07b..99b2fbbcc 100644 --- a/libxcb/src/xcb_auth.c +++ b/libxcb/src/xcb_auth.c @@ -25,6 +25,10 @@ /* Authorization systems for the X protocol. */ +#ifdef WIN32 +#define INCL_WINSOCK_API_TYPEDEFS 1 /* Needed for LPFN_GETPEERNAME */ +#endif + #include <assert.h> #include <X11/Xauth.h> #include <sys/socket.h> @@ -89,8 +93,7 @@ static int authname_match(enum auth_protos kind, char *name, size_t namelen) #define SIN6_ADDR(s) (&((struct sockaddr_in6 *)s)->sin6_addr) -static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen, - int display) +static Xauth *get_authptr(struct sockaddr *sockname, int display) { char *addr = 0; int addrlen = 0; @@ -243,13 +246,56 @@ static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr * return 0; /* Unknown authorization type */ } +/* `sockaddr_un.sun_path' typical size usually ranges between 92 and 108 */ +#define INITIAL_SOCKNAME_SLACK 108 + +#ifndef WIN32 +typedef int (*LPFN_GETPEERNAME)(int,struct sockaddr *,socklen_t *); +#endif +/* Return a dynamically allocated socket address structure according + to the value returned by either getpeername() or getsockname() + (according to POSIX, applications should not assume a particular + length for `sockaddr_un.sun_path') */ +static struct sockaddr *get_peer_sock_name(LPFN_GETPEERNAME socket_func, + int fd) +{ + socklen_t socknamelen = sizeof(struct sockaddr) + INITIAL_SOCKNAME_SLACK; + socklen_t actual_socknamelen = socknamelen; + struct sockaddr *sockname = malloc(socknamelen), *new_sockname = NULL; + + if (sockname == NULL) + return NULL; + + /* Both getpeername() and getsockname() truncates sockname if + there is not enough space and set the required length in + actual_socknamelen */ + if (socket_func(fd, sockname, &actual_socknamelen) == -1) + goto sock_or_realloc_error; + + if (actual_socknamelen > socknamelen) + { + socknamelen = actual_socknamelen; + + if ((new_sockname = realloc(sockname, actual_socknamelen)) == NULL || + socket_func(fd, new_sockname, &actual_socknamelen) == -1 || + actual_socknamelen > socknamelen) + goto sock_or_realloc_error; + + sockname = new_sockname; + } + + return sockname; + + sock_or_realloc_error: + free(sockname); + return NULL; +} + int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display) { /* code adapted from Xlib/ConnDis.c, xtrans/Xtranssocket.c, xtrans/Xtransutils.c */ - char sockbuf[sizeof(struct sockaddr) + MAXPATHLEN]; - unsigned int socknamelen = sizeof(sockbuf); /* need extra space */ - struct sockaddr *sockname = (struct sockaddr *) &sockbuf; + struct sockaddr *sockname = NULL; int gotsockname = 0; Xauth *authptr = 0; int ret = 1; @@ -258,24 +304,30 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display) * for UNIX Domain Sockets, but this is irrelevant, * since compute_auth() ignores the peer name in this * case anyway.*/ - if (getpeername(fd, sockname, &socknamelen) == -1) + if ((sockname = get_peer_sock_name(getpeername, fd)) == NULL) { + if ((sockname = get_peer_sock_name(getsockname, fd)) == NULL) + return 0; /* can only authenticate sockets */ if (sockname->sa_family != AF_UNIX) + { + free(sockname); return 0; /* except for AF_UNIX, sockets should have peernames */ - if (getsockname(fd, sockname, &socknamelen) == -1) - return 0; /* can only authenticate sockets */ + } gotsockname = 1; } - authptr = get_authptr(sockname, socknamelen, display); + authptr = get_authptr(sockname, display); if (authptr == 0) + { + free(sockname); return 0; /* cannot find good auth data */ + } info->namelen = memdup(&info->name, authptr->name, authptr->name_length); if (!info->namelen) goto no_auth; /* out of memory */ - if (!gotsockname && getsockname(fd, sockname, &socknamelen) == -1) + if (!gotsockname && (sockname = get_peer_sock_name(getsockname, fd)) == NULL) { free(info->name); goto no_auth; /* can only authenticate sockets */ @@ -288,10 +340,15 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display) goto no_auth; /* cannot build auth record */ } + free(sockname); + sockname = NULL; + XauDisposeAuth(authptr); return ret; no_auth: + free(sockname); + info->name = 0; info->namelen = 0; XauDisposeAuth(authptr); diff --git a/libxcb/src/xcb_util.c b/libxcb/src/xcb_util.c index 78bab5c5d..101532be3 100644 --- a/libxcb/src/xcb_util.c +++ b/libxcb/src/xcb_util.c @@ -143,13 +143,12 @@ static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen); static int _xcb_open(char *host, char *protocol, const int display) { -#ifdef HAVE_ABSTRACT_SOCKETS int fd; -#endif static const char unix_base[] = "/tmp/.X11-unix/X"; const char *base = unix_base; - char file[PATH_MAX + 1]; - int filelen; + size_t filelen; + char *file = NULL; + int actual_filelen; if(*host) { @@ -184,24 +183,38 @@ static int _xcb_open(char *host, char *protocol, const int display) #endif } + filelen = strlen(base) + 1 + sizeof(display) * 3 + 1; + file = malloc(filelen); + if(file == NULL) + return -1; + /* display specifies Unix socket */ #ifdef HAVE_LAUNCHD if(base == host) - filelen = snprintf(file, sizeof(file), "%s:%d", base, display); + actual_filelen = snprintf(file, filelen, "%s:%d", base, display); else #endif - filelen = snprintf(file, sizeof(file), "%s%d", base, display); - if(filelen < 0) + actual_filelen = snprintf(file, filelen, "%s%d", base, display); + if(actual_filelen < 0) + { + free(file); return -1; + } /* snprintf may truncate the file */ - filelen = MIN(filelen, sizeof(file) - 1); + filelen = MIN(actual_filelen, filelen - 1); #ifdef HAVE_ABSTRACT_SOCKETS fd = _xcb_open_abstract(protocol, file, filelen); if (fd >= 0 || (errno != ENOENT && errno != ECONNREFUSED)) + { + free(file); return fd; + } #endif - return _xcb_open_unix(protocol, file); + fd = _xcb_open_unix(protocol, file); + free(file); + + return fd; } #ifdef DNETCONN |