X-Git-Url: http://git.demorecorder.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fxcb_auth.c;h=d774d106942bf46e157e91e73f995c4f9e274a63;hb=1c590d5a86ae854e53f388e40c952e92f11d59e6;hp=a648b16bc69d957f6b7113e2b67c2f9c7c6d0a93;hpb=9f24c91f91dd68a52e46191b686283b0df38d2f5;p=free-sw%2Fxcb%2Flibxcb diff --git a/src/xcb_auth.c b/src/xcb_auth.c index a648b16..d774d10 100644 --- a/src/xcb_auth.c +++ b/src/xcb_auth.c @@ -89,14 +89,14 @@ 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; unsigned short family; char hostnamebuf[256]; /* big enough for max hostname */ char dispbuf[40]; /* big enough to hold more than 2^64 base 10 */ + int dispbuflen; family = FamilyLocal; /* 256 */ switch(sockname->sa_family) @@ -127,7 +127,11 @@ static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen, return 0; /* cannot authenticate this family */ } - snprintf(dispbuf, sizeof(dispbuf), "%d", display); + dispbuflen = snprintf(dispbuf, sizeof(dispbuf), "%d", display); + if(dispbuflen < 0) + return 0; + /* snprintf may have truncate our text */ + dispbuflen = MIN(dispbuflen, sizeof(dispbuf) - 1); if (family == FamilyLocal) { if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) @@ -138,7 +142,7 @@ static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen, return XauGetBestAuthByAddr (family, (unsigned short) addrlen, addr, - (unsigned short) strlen(dispbuf), dispbuf, + (unsigned short) dispbuflen, dispbuf, N_AUTH_PROTOS, authnames, authnameslen); } @@ -238,39 +242,110 @@ 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 + +/* 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(int (*socket_func)(int, + struct sockaddr *, + socklen_t *), + 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; - if (getpeername(fd, sockname, &socknamelen) == -1) + /* Some systems like hpux or Hurd do not expose peer names + * for UNIX Domain Sockets, but this is irrelevant, + * since compute_auth() ignores the peer name in this + * case anyway.*/ + if ((sockname = get_peer_sock_name(getpeername, fd)) == NULL) { - if (getsockname(fd, sockname, &socknamelen) == -1) - return 0; /* can only authenticate sockets */ + if ((sockname = get_peer_sock_name(getsockname, fd)) == NULL) + return 0; /* can only authenticate sockets */ if (sockname->sa_family != AF_UNIX) - return 0; - /* Some systems like hpux or Hurd do not expose peer names - * for UNIX Domain Sockets. We do not need it anyway. */ + { + 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) - ret = compute_auth(info, authptr, sockname); + if (!info->namelen) + goto no_auth; /* out of memory */ + + if (!gotsockname && (sockname = get_peer_sock_name(getsockname, fd)) == NULL) + { + free(info->name); + goto no_auth; /* can only authenticate sockets */ + } + + ret = compute_auth(info, authptr, sockname); if(!ret) { - free(info->name); - info->name = 0; - info->namelen = 0; + free(info->name); + 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); + return 0; }