diff --git a/src/xcb_auth.c b/src/xcb_auth.c index 00aad23..bee4620 100644 --- a/src/xcb_auth.c +++ b/src/xcb_auth.c @@ -89,8 +89,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 +242,47 @@ static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr * return 0; /* Unknown authorization type */ } +/* Return a dynamically allocated socket address structure according + to the value returned by either getpeername() or getsockname() */ +static struct sockaddr *get_peer_sock_name(int (*socket_func)(int, + struct sockaddr *, + socklen_t *), + int fd) +{ + socklen_t socknamelen = sizeof(struct sockaddr) + 1024; + socklen_t actual_socknamelen = socknamelen; + int socket_func_ret; + struct sockaddr *sockname = malloc(socknamelen); + + 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 */ + while ((socket_func_ret = socket_func(fd, sockname, + &actual_socknamelen)) != -1 && + actual_socknamelen > socknamelen) + { + socknamelen = actual_socknamelen; + /* Adjust sockname size according to the required one */ + sockname = realloc(sockname, socknamelen); + } + + if (socket_func_ret == -1) + { + free(sockname); + return NULL; + } + + return sockname; +} + 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 +291,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 (getsockname(fd, sockname, &socknamelen) == -1) + 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 */ + } 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 +327,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/src/xcb_util.c b/src/xcb_util.c index 287f12f..cc4e24a 100644 --- a/src/xcb_util.c +++ b/src/xcb_util.c @@ -145,8 +145,9 @@ static int _xcb_open(char *host, char *protocol, const int display) #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) { @@ -181,24 +182,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; } static int _xcb_socket(int family, int type, int proto)