2 * libauthbind.c - bind(2)-redirector library for authbind
4 * authbind is Copyright (C) 1998 Ian Jackson
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)
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.
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.
26 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <netinet/in.h>
36 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
37 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
39 typedef void anyfn_type(void);
41 static anyfn_type *find_any(const char *name) {
42 static const char *dlerr;
45 kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
46 dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
47 STDERRSTR_CONST("libauthbind: error finding original version of ");
48 STDERRSTR_STRING(name);
49 STDERRSTR_CONST(": ");
50 STDERRSTR_STRING(dlerr);
51 STDERRSTR_STRING("\n");
56 #define socket_args int domain, int type, int protocol
57 #define WRAPS(X) X(socket, (domain,type,protocol))
59 #define DEF_OLD(fn,args) \
60 typedef int fn##_fn_type(fn##_args); \
61 static int find_##fn(fn##_args); \
62 static fn##_fn_type find_##fn, *old_##fn=find_##fn; \
63 static int find_##fn(fn##_args) { \
65 anyfn= find_any(#fn); if (!anyfn) return -1; \
66 old_##fn= (fn##_fn_type*)anyfn; \
67 return old_##fn args; \
72 #define WRAP(fn) int fn(fn##_args)
75 return old_socket(domain,type,protocol);
79 WRAP(bind, (int fd, const struct sockaddr *addr, socklen_t addrlen), {
83 static bindfn_type find_bind, *old_bind= find_bind;
85 int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
87 anyfn= find_any("bind"); if (!anyfn) return -1;
88 old_bind= (bindfn_type*)anyfn;
89 return old_bind(fd,addr,addrlen);
92 static int exiterrno(int e) {
93 _exit(e>0 && e<128 ? e : -1);
96 static void removepreload(void) {
97 const char *myself, *found;
98 char *newval, *preload;
99 int lpreload, lmyself, before, after;
101 preload= getenv(PRELOAD_VAR);
102 myself= getenv(AUTHBINDLIB_VAR);
103 if (!myself || !preload) return;
105 lpreload= strlen(preload);
106 lmyself= strlen(myself);
108 if (lmyself < 1 || lpreload<lmyself) return;
109 if (lpreload==lmyself) {
110 if (!strcmp(preload,myself)) unsetenv(PRELOAD_VAR);
113 if (!memcmp(preload,myself,lmyself) && preload[lmyself]==':') {
114 before= 0; after= lpreload-(lmyself+1);
115 } else if (!memcmp(preload+lpreload-lmyself,myself,lmyself) &&
116 preload[lpreload-(lmyself+1)]==':') {
117 before= lpreload-(lmyself+1); after= 0;
119 if (lpreload<lmyself+2) return;
122 found= strstr(found,myself); if (!found) return;
123 if (found > preload+lpreload-(lmyself+1)) return;
124 if (found[-1]==':' && found[lmyself]==':') break;
127 before= found-preload;
128 after= lpreload-(before+lmyself+1);
130 newval= malloc(before+after+1);
132 memcpy(newval,preload,before);
133 strcpy(newval+before,preload+lpreload-after);
134 if (setenv(PRELOAD_VAR,newval,1)) return;
137 strcpy(preload+before,preload+lpreload-after);
146 /* If AUTHBIND_LEVELS is
147 * unset => always strip from preload
148 * set and starts with `y' => never strip from preload, keep AUTHBIND_LEVELS
149 * set to integer > 1 => do not strip now, subtract one from AUTHBIND_LEVELS
150 * set to integer 1 => do not strip now, unset AUTHBIND_LEVELS
151 * set to empty string or 0 => strip now, unset AUTHBIND_LEVELS
153 levels= getenv(AUTHBIND_LEVELS_VAR);
155 if (levels[0]=='y') return 0;
156 levelno= atoi(levels);
159 if (levelno > 0) sprintf(levels,"%d",levelno);
160 else unsetenv(AUTHBIND_LEVELS_VAR);
163 unsetenv(AUTHBIND_LEVELS_VAR);
169 static const int evilsignals[]= { SIGFPE, SIGILL, SIGSEGV, SIGBUS, 0 };
171 int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
173 char portarg[5], addrarg[33];
175 int i, r, status, restore_sigchild;
176 const int *evilsignal;
177 sigset_t block, saved;
178 struct sigaction old_sigchild;
179 unsigned int portval;
181 switch (addr->sa_family) {
183 portval = ((struct sockaddr_in*)addr)->sin_port;
184 if (addrlen != sizeof(struct sockaddr_in)) goto bail;
187 portval = ((struct sockaddr_in6*)addr)->sin6_port;
188 if (addrlen != sizeof(struct sockaddr_in6)) goto bail;
194 if (!geteuid() || portval == 0 || ntohs(portval) >= IPPORT_RESERVED) {
196 return old_bind(fd,addr,addrlen);
200 for (evilsignal=evilsignals;
203 sigdelset(&block,*evilsignal);
204 if (sigprocmask(SIG_BLOCK,&block,&saved)) return -1;
206 switch (addr->sa_family) {
209 sprintf(addrarg,"%08lx",
210 ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))
216 sprintf(addrarg+i*2,"%02x",
217 ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr[i]);
222 sprintf(portarg,"%04x",
226 if (sigaction(SIGCHLD,NULL,&old_sigchild)) return -1;
227 if (old_sigchild.sa_handler == SIG_IGN) {
228 struct sigaction new_sigchild;
230 new_sigchild.sa_handler= SIG_DFL;
231 sigemptyset(&new_sigchild.sa_mask);
232 new_sigchild.sa_flags= 0;
233 if (sigaction(SIGCHLD,&new_sigchild,&old_sigchild)) return -1;
237 child= fork(); if (child==-1) goto x_err;
240 if (dup2(fd,0)) exiterrno(errno);
242 execl(HELPER,HELPER,addrarg,portarg,afarg,(char*)0);
243 status= errno > 0 && errno < 127 ? errno : 127;
244 STDERRSTR_CONST("libauthbind: possible installation problem - "
245 "could not invoke " HELPER "\n");
249 rchild= waitpid(child,&status,0);
250 if (rchild==-1) goto x_err;
251 if (rchild!=child) { errno= ECHILD; goto x_err; }
253 if (WIFEXITED(status)) {
254 if (WEXITSTATUS(status)) {
255 errno= WEXITSTATUS(status);
256 if (errno >= 127) errno= ENXIO;
269 if (sigprocmask(SIG_SETMASK,&saved,0)) abort();
270 if (restore_sigchild) {
271 if (sigaction(SIGCHLD,&old_sigchild,NULL)) return -1;
272 if (old_sigchild.sa_handler == SIG_IGN) {
274 while (waitpid(-1, &discard, WNOHANG) > 0)