chiark / gitweb /
7cfd91ad48e14e8fdfbfc7a5eaa10241f8acc949
[authbind.git] / helper.c
1 /*
2  *  helper.c - setuid helper program for authbind
3  *
4  *  authbind is Copyright (C) 1998 Ian Jackson
5  * 
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  * 
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  * 
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software Foundation,
18  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
19  * 
20  */
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32
33 #ifndef CONFIGDIR
34 # define CONFIGDIR "/etc/authbind"
35 #endif
36
37 static const char *rcsid="$Id$";
38
39 static void exiterrno(int e) {
40   exit(e>0 && e<128 ? e : ENOSYS);
41 }
42
43 static void perrorfail(const char *m) {
44   int e;
45   e= errno;
46   fprintf(stderr,"libauthbind's helper: %s: %s\n",m,strerror(e));
47   exiterrno(e);
48 }
49
50 static void badusage(void) {
51   fprintf(stderr,"libauthbind's helper: bad usage\n (%s)\n",rcsid);
52   exit(ENOSYS);
53 }
54
55 static struct sockaddr_in saddr4;
56
57 static void authorised(void) {
58   if (bind(0,&saddr4,sizeof(saddr4))) exiterrno(errno);
59   else _exit(0);
60 }
61
62 int main(int argc, const char *const *argv) {
63   uid_t uid;
64   char fnbuf[100];
65   char *ep;
66   const char *np;
67   unsigned long addr, port, haddr, thaddr, thmask;
68   unsigned int hport, a1,a2,a3,a4, alen,pmin,pmax;
69   int nchar;
70   FILE *file;
71
72   if (argc != 3) badusage(); 
73   addr= strtoul(argv[1],&ep,16); if (*ep || addr&~0x0ffffffffUL) badusage();
74   port= strtoul(argv[2],&ep,16); if (*ep || port&~0x0ffffUL) badusage();
75   hport= htons(port);
76   if (hport >= IPPORT_RESERVED/2) _exit(EPERM);
77
78   if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR);
79
80   fnbuf[sizeof(fnbuf)-1]= 0;
81   memset(&saddr4,0,sizeof(saddr4));
82   saddr4.sin_family= AF_INET;
83   saddr4.sin_port= port;
84   saddr4.sin_addr.s_addr= addr;
85
86   snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%u",hport);
87   if (!access(fnbuf,X_OK)) authorised();
88   if (errno != ENOENT) exiterrno(errno);
89
90   np= inet_ntoa(saddr4.sin_addr); assert(np);
91   snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%u",np,hport);
92   if (!access(fnbuf,X_OK)) authorised();
93   if (errno != ENOENT) exiterrno(errno);
94
95   uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid");
96   snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%lu",(unsigned long)uid);
97
98   file= fopen(fnbuf,"r");
99   if (!file) exiterrno(errno==ENOENT ? EPERM : errno);
100
101   haddr= ntohl(addr);
102
103   while (fgets(fnbuf,sizeof(fnbuf)-1,file)) {
104     nchar= -1;
105     sscanf(fnbuf," %u.%u.%u.%u/%u:%u,%u %n",
106            &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar);
107     if (nchar != strlen(fnbuf) ||
108         alen>32 || pmin&~0x0ffff || pmax&~0x0ffff ||
109         a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff)
110       continue;
111     
112     if (hport<pmin || hport>pmax) continue;
113
114     thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4);
115     thmask= 0x0ffffffffUL<<(32-alen);
116     if ((haddr&thmask) != thaddr) continue;
117     authorised();
118   }
119   if (ferror(file)) perrorfail("read per-uid file");
120   _exit(ENOENT);
121 }