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.
24 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
33 static const char *rcsid="$Id$";
37 typedef void anyfn_type(void);
38 typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen);
40 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
41 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
43 static int find_any(const char *name, anyfn_type **keep) {
44 static const char *dlerr;
48 kv= dlsym(RTLD_NEXT,name);
49 if (kv) { *keep= kv; return 0; }
50 dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
51 STDERRSTR_CONST("libauthbind: error finding original version of ");
52 STDERRSTR_STRING(name);
53 STDERRSTR_CONST(": ");
54 STDERRSTR_STRING(dlerr);
55 STDERRSTR_STRING("\n");
60 static bindfn_type find_bind, *old_bind= find_bind;
62 int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
64 if (find_any("bind",&anyfn)) return -1;
65 old_bind= (bindfn_type*)anyfn;
66 return old_bind(fd,addr,addrlen);
69 static int exiterrno(int e) {
70 _exit(e>0 && e<128 ? e : -1);
73 static void removepreload(void) {
74 const char *myself, *found;
75 char *newval, *preload;
76 int lpreload, lmyself, before, after;
78 preload= getenv(PRELOAD_VAR);
79 myself= getenv(AUTHBINDLIB_VAR);
80 if (!myself || !preload) return;
82 lpreload= strlen(preload);
83 lmyself= strlen(myself);
85 if (lmyself < 1 || lpreload<lmyself) return;
86 if (lpreload==lmyself) {
87 if (!strcmp(preload,myself)) unsetenv(PRELOAD_VAR);
90 if (!memcmp(preload,myself,lmyself) && preload[lmyself]==':') {
91 before= 0; after= lpreload-(lmyself+1);
92 } else if (!memcmp(preload+lpreload-lmyself,myself,lmyself) &&
93 preload[lpreload-(lmyself+1)]==':') {
94 before= lpreload-(lmyself+1); after= 0;
96 if (lpreload<lmyself+2) return;
99 found= strstr(found,myself); if (!found) return;
100 if (found > preload+lpreload-(lmyself+1)) return;
101 if (found[-1]==':' && found[lmyself]==':') break;
104 before= found-preload;
105 after= lpreload-(before+lmyself+1);
107 newval= malloc(before+after+1);
109 memcpy(newval,preload,before);
110 strcpy(newval+before,preload+lpreload-after);
111 if (setenv(PRELOAD_VAR,newval,1)) return;
114 strcpy(preload+before,preload+lpreload-after);
123 /* If AUTHBIND_LEVELS is
124 * unset => always strip from preload
125 * set and starts with `y' => never strip from preload, keep AUTHBIND_LEVELS
126 * set to integer > 1 => do not strip now, subtract one from AUTHBIND_LEVELS
127 * set to integer 1 => do not strip now, unset AUTHBIND_LEVELS
128 * set to empty string or 0 => strip now, unset AUTHBIND_LEVELS
130 levels= getenv(AUTHBIND_LEVELS_VAR);
132 if (levels[0]=='y') return 0;
133 levelno= atoi(levels);
136 if (levelno > 0) sprintf(levels,"%d",levelno);
137 else unsetenv(AUTHBIND_LEVELS_VAR);
140 unsetenv(AUTHBIND_LEVELS_VAR);
146 int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
148 char portarg[5], addrarg[9];
151 if (addr->sa_family != AF_INET || addrlen != sizeof(struct sockaddr_in) ||
152 ntohs(((struct sockaddr_in*)addr)->sin_port) >= IPPORT_RESERVED/2 || !geteuid())
153 return old_bind(fd,addr,addrlen);
155 sprintf(addrarg,"%08lx",
156 ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL);
157 sprintf(portarg,"%04x",
158 ((unsigned int)(((struct sockaddr_in*)addr)->sin_port))&0x0ffff);
160 child= fork(); if (child==-1) return -1;
163 if (dup2(fd,0)) exiterrno(errno);
165 execl(HELPER,HELPER,addrarg,portarg,(char*)0);
167 STDERRSTR_CONST("libauthbind: possible installation problem - "
168 "could not invoke " HELPER " (");
169 STDERRSTR_STRING(rcsid);
170 STDERRSTR_CONST(")\n");
174 rchild= waitpid(child,&status,0);
175 if (rchild==-1) return -1;
176 if (rchild!=child) { errno= ECHILD; return -1; }
178 if (WIFEXITED(status)) {
179 if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; }