From ea186a6c113d2397f73596952a65ecd4e3d51c76 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 1 Jun 2012 23:29:44 +0100 Subject: [PATCH] wip v6 support etc. --- authbind.1 | 35 +++++++++----- helper.c | 131 +++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 129 insertions(+), 37 deletions(-) diff --git a/authbind.1 b/authbind.1 index 2b372ea..09f9fc2 100644 --- a/authbind.1 +++ b/authbind.1 @@ -65,7 +65,7 @@ of files in a configuration area, .BR /etc/authbind . .PP Firstly, -.BI /etc/authbind/byport/ port +.BR /etc/authbind/byport/ [ ! ]\fIport\fR is tested. If this file is accessible for execution to the calling user, according to .BR access (2), @@ -84,11 +84,11 @@ call, usually .RI ( "Permission denied" ). .PP Secondly, if that test fails to resolve the matter, -.BI /etc/authbind/byaddr/ addr : port +.BR /etc/authbind/byaddr/ \fIaddr\fR : [ ! ]\fIport\fR is tested, in the same manner as above. .PP Thirdly, if the question is still unresolved, the file -.BI /etc/authbind/byuid/ uid +.BR /etc/authbind/byuid/ [ ! ]\fIuid\fR will be opened and read. If the file does not exist then the binding is not authorised and .B bind @@ -97,15 +97,19 @@ will return .RI ( "Operation not permitted" ", or " "Not owner" ). If the file does exist it will be searched for a line of the form .nf -.IB addr / length : min\-port , max\-port +.IB addr4 / length : min\-port , max\-port +.IR addrmin [\fB-\fR addrmax ]\fB:\fR min\-port \fB,\fR max\-port .fi -matching the request (ie, the initial +matching the request. The first form requires that the initial .I length bits of .I addr match those in the proposed .B bind -call, and the proposed port number lies is in the inclusive range +call. The second form requires that the address lies in the +relevant range (inclusive at both ends). Addresses can +be in any form acceptable to inet_pton. In both cases +the proposed port number must lie is in the inclusive range specified. If such a line is found then the binding is authorised. Otherwise it is not, and .B bind @@ -134,6 +138,17 @@ files are silently ignored (as are lines whose has non-zero bits more than .I length from the top). +.TP +Authorising binding to ports from 512 to 1023 inclusive is +not recommended. Some protocols (including some versions of NFS) +authorise clients by seeing that they are using a port number in this +range. So by authorising a program to be a server for such a port, +you are also authorising it to impersonate the whole host for those +protocols. To make sure that this isn't done by accident, +if the port number requested is in the range 512-1023, all the files +checked and read will have the additional +.B ! +character. .SH MECHANISM The shared library loaded using .B LD_PRELOAD @@ -178,7 +193,8 @@ the program's stderr, was well as returning -1 from .BR bind . .SH BUGS .B authbind -currently only supports IPv4 sockets. Programs which open other kinds +currently only supports IPv4 and IPv6 sockets. +Programs which open other kinds of sockets will not benefit from .BR authbind , but it won't get in their way. @@ -234,11 +250,6 @@ to happen and signal to be delivered. Programs should not rely on standard libraries not doing these things. .PP -Ports from 512 to 1023 inclusive cannot be used with -.B authbind -because that would create a security hole, in conjection with -.BR rshd . -.PP The access control configuration scheme is somewhat strange. .SH FILES AND ENVIRONMENT VARIABLES .TP diff --git a/helper.c b/helper.c index 7cfd91a..7c50551 100644 --- a/helper.c +++ b/helper.c @@ -53,67 +53,148 @@ static void badusage(void) { } static struct sockaddr_in saddr4; +static struct sockaddr_in6 saddr6; + +static struct sockaddr *saddr_any; +static const void *addr_any; +static size_t saddrlen_any, addrlen_any; static void authorised(void) { - if (bind(0,&saddr4,sizeof(saddr4))) exiterrno(errno); + if (bind(0,saddr_any,saddrlen_any)) exiterrno(errno); else _exit(0); } +static void hex2bytes(const char *string, unsigned char *out, int len) { + int i; + for (i=0; i= IPPORT_RESERVED/2) _exit(EPERM); + if (hport >= IPPORT_RESERVED/2) tophalfchar= "!"; if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR); fnbuf[sizeof(fnbuf)-1]= 0; - memset(&saddr4,0,sizeof(saddr4)); - saddr4.sin_family= AF_INET; - saddr4.sin_port= port; - saddr4.sin_addr.s_addr= addr; - snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%u",hport); + switch (af) { + case AF_INET: + saddr4.sin_family= af; + saddr4.sin_port= port; + saddr4.sin_addr.s_addr= addr4; + break; + case AF_INET6: + saddr6.sin6_family= af; + saddr6.sin6_port= port; + break; + default: + abort(); + } + + snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%s%u",tophalfchar,hport); if (!access(fnbuf,X_OK)) authorised(); if (errno != ENOENT) exiterrno(errno); - np= inet_ntoa(saddr4.sin_addr); assert(np); - snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%u",np,hport); + char npbuf[INET_ADDRSTRLEN + INET6_ADDRSTRLEN]; + np= inet_ntop(af,addr_any,npbuf,addrlen_any); + assert(np); + + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%s%u",np,tophalfchar,hport); if (!access(fnbuf,X_OK)) authorised(); if (errno != ENOENT) exiterrno(errno); uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid"); - snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%lu",(unsigned long)uid); + snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%s%lu",tophalfchar,(unsigned long)uid); file= fopen(fnbuf,"r"); if (!file) exiterrno(errno==ENOENT ? EPERM : errno); - haddr= ntohl(addr); - while (fgets(fnbuf,sizeof(fnbuf)-1,file)) { nchar= -1; - sscanf(fnbuf," %u.%u.%u.%u/%u:%u,%u %n", - &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar); - if (nchar != strlen(fnbuf) || - alen>32 || pmin&~0x0ffff || pmax&~0x0ffff || - a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff) + + char *colon = strchr(fnbuf,'/'); + if (!colon) continue; + *colon++ = '\0'; + + sscanf(fnbuf," %u.%u.%u.%u/%u%n", + &a1,&a2,&a3,&a4,&alen,&nchar); + if (nchar == strlen(fnbuf)) { + if (alen>32 || pmin&~0x0ffff || pmax&~0x0ffff || + a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff) + continue; + + unsigned long thaddr, thmask; + thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4); + thmask= 0x0ffffffffUL<<(32-alen); + if ((haddr4&thmask) != thaddr) continue; + } else { + char *hyphen = strchr(fnbuf,'-'); + const char *min, *max; + if (hyphen) { + *hyphen++ = '\0'; + min = fnbuf; + max = hyphen; + } else { + min = fnbuf; + max = fnbuf; + } + unsigned char minaddr[addrlen_any]; + unsigned char maxaddr[addrlen_any]; + if (inet_pton(af,min,minaddr) != 1 || + inet_pton(af,max,maxaddr) != 1) + continue; + if (memcmp(addr_any,minaddr,addrlen_any) < 0 || + memcmp(addr_any,maxaddr,addrlen_any) > 0) + continue; + } + + sscanf(colon," %u,%u %n", + &pmin,&pmax,&nchar); + if (nchar != strlen(colon)) continue; if (hportpmax) continue; - thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4); - thmask= 0x0ffffffffUL<<(32-alen); - if ((haddr&thmask) != thaddr) continue; authorised(); } if (ferror(file)) perrorfail("read per-uid file"); -- 2.30.2