2 * setuid. Invoked with socket on stdin.
3 * Usage: helper <addr> <port>
4 * both are hex strings, padded to the right length.
5 * they are pairs of hex digits for each byte (network byte order)
7 * If /etc/authbind cannot be chdir'd into, is an error.
9 * First, check /etc/authbind/byport/<port> with access(2,X_OK).
10 * If OK, then authorised.
11 * If ENOENT then keep looking.
12 * Otherwise, not authorised, errno=whatever
14 * Then check /etc/authbind/byboth/<addr>:<port> likewise.
16 * Then try to read /etc/authbind/byuid/<uid> (with superuser privs!)
17 * If ENOENT, then not authorised, errno=EPERM
18 * If cannot open, then not authorised, errno=whatever
19 * If it contains a line of the form
20 * <addr>/<length>:<port-min>,<port-max>
21 * then authorised, otherwise not authorised, errno=ENOENT
22 * If read error then is an error
25 * <addr> is dotted quad
26 * <port> is decimal in host order
27 * <length> is prefix length (so 0.0.0.0/32 matches any)
28 * <uid> is decimal unsigned
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #define CONFIGDIR "/etc/authbind"
44 static void exiterrno(int e) {
45 exit(e>0 && e<128 ? e : ENOSYS);
48 static void perrorfail(const char *m) {
51 fprintf(stderr,"libauthbind's helper: %s: %s\n",m,strerror(e));
55 static void badusage(void) {
56 fputs("libauthbind's helper: bad usage\n",stderr);
60 static struct sockaddr_in saddr;
62 static void authorised(void) {
63 if (bind(0,&saddr,sizeof(saddr))) exiterrno(errno);
67 int main(int argc, const char *const *argv) {
72 unsigned long addr, port, haddr, thaddr, thmask;
73 unsigned int hport, a1,a2,a3,a4, alen,pmin,pmax;
77 if (argc != 3) badusage();
78 addr= strtoul(argv[1],&ep,16); if (*ep || addr&~0x0ffffffffUL) badusage();
79 port= strtoul(argv[2],&ep,16); if (*ep || port&~0x0ffffUL) badusage();
81 if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR);
83 fnbuf[sizeof(fnbuf)-1]= 0;
84 memset(&saddr,0,sizeof(saddr));
85 saddr.sin_family= AF_INET;
87 saddr.sin_addr.s_addr= addr;
90 snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%u",hport);
91 if (!access(fnbuf,X_OK)) authorised();
92 if (errno != ENOENT) exiterrno(errno);
94 np= inet_ntoa(saddr.sin_addr); assert(np);
95 snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%u",np,hport);
96 if (!access(fnbuf,X_OK)) authorised();
97 if (errno != ENOENT) exiterrno(errno);
99 uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid");
100 snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%lu",(unsigned long)uid);
102 file= fopen(fnbuf,"r");
103 if (!file) exiterrno(errno==ENOENT ? EPERM : errno);
107 while (fgets(fnbuf,sizeof(fnbuf)-1,file)) {
109 sscanf(fnbuf," %u.%u.%u.%u/%u:%u,%u %n",
110 &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar);
111 if (nchar != strlen(fnbuf) ||
112 alen>32 || pmin&~0x0ffff || pmax&~0x0ffff ||
113 a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff)
116 if (hport<pmin || hport>pmax) continue;
118 thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4);
119 thmask= 0x0ffffffffUL<<(32-alen);
120 if ((haddr&thmask) != thaddr) continue;
123 if (ferror(file)) perrorfail("read per-uid file");