chiark / gitweb /
3bdd58f9d89b546c2725e49c7d9dcb5d93d19836
[authbind.git] / libauthbind.c
1 /*
2  *  libauthbind.c - bind(2)-redirector library 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 <dlfcn.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <sys/wait.h>
31 #include <netinet/in.h>
32
33 static const char *rcsid="$Id$";
34
35 #ifndef HELPER
36 # define HELPER "/usr/local/lib/authbind/helper"
37 #endif
38
39 #define AUTHBIND_NESTED_VAR "AUTHBIND_NESTED"
40
41 typedef void anyfn_type(void);
42 typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen);
43
44 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
45 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
46
47 static int find_any(const char *name, anyfn_type **keep) {
48   static const char *dlerr;
49   anyfn_type *kv;
50
51   if (*keep) return 0;
52   kv= dlsym(RTLD_NEXT,name);
53   if (kv) { *keep= kv; return 0; }
54   dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
55   STDERRSTR_CONST("libauthbind: error finding original version of ");
56   STDERRSTR_STRING(name);
57   STDERRSTR_CONST(": ");
58   STDERRSTR_STRING(dlerr);
59   STDERRSTR_STRING("\n");
60   errno= ENOSYS;
61   return -1;
62 }
63
64 static bindfn_type find_bind, *old_bind= find_bind;
65
66 int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
67   anyfn_type *anyfn;
68   if (find_any("bind",&anyfn)) return -1;
69   old_bind= (bindfn_type*)anyfn;
70   return old_bind(fd,addr,addrlen);
71 }
72
73 static int exiterrno(int e) {
74   _exit(e>0 && e<128 ? e : -1);
75 }
76
77 int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
78   pid_t child, rchild;
79   char portarg[5], addrarg[9];
80   int status;
81   
82   if (addr->sa_family != AF_INET || addrlen != sizeof(struct sockaddr_in) ||
83       ntohs(((struct sockaddr_in*)addr)->sin_port) >= IPPORT_RESERVED/2 || !geteuid())
84     return old_bind(fd,addr,addrlen);
85
86   if (getenv(AUTHBIND_NESTED_VAR)) {
87     STDERRSTR_CONST("libauthbind: possible installation problem - "
88                     "nested invocation, perhaps helper is not setuid\n ");
89     STDERRSTR_STRING(rcsid);
90     STDERRSTR_CONST("\n");
91     return old_bind(fd,addr,addrlen);
92   }
93
94   sprintf(addrarg,"%08lx",
95           ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL);
96   sprintf(portarg,"%04x",
97           ((unsigned int)(((struct sockaddr_in*)addr)->sin_port))&0x0ffff);
98
99   child= fork(); if (child==-1) return -1;
100
101   if (!child) {
102     if (dup2(fd,0)) exiterrno(errno);
103     if (setenv(AUTHBIND_NESTED_VAR,"1",1)) exiterrno(errno);
104     execl(HELPER,HELPER,addrarg,portarg,(char*)0);
105     status= errno;
106     STDERRSTR_CONST("libauthbind: possible installation problem - "
107                     "could not invoke " HELPER "\n");
108     exiterrno(status);
109   }
110
111   rchild= waitpid(child,&status,0);
112   if (rchild==-1) return -1;
113   if (rchild!=child) { errno= ECHILD; return -1; }
114
115   if (WIFEXITED(status)) {
116     if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; }
117     return 0;
118   } else {
119     errno= ENOSYS;
120     return -1;
121   }
122 }