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 anyfn_type *find_any(const char *name) {
44 static const char *dlerr;
47 kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
48 dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
49 STDERRSTR_CONST("libauthbind: error finding original version of ");
50 STDERRSTR_STRING(name);
51 STDERRSTR_CONST(": ");
52 STDERRSTR_STRING(dlerr);
53 STDERRSTR_STRING("\n");
58 static bindfn_type find_bind, *old_bind= find_bind;
60 int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
62 anyfn= find_any("bind"); if (!anyfn) return -1;
63 old_bind= (bindfn_type*)anyfn;
64 return old_bind(fd,addr,addrlen);
67 static int exiterrno(int e) {
68 _exit(e>0 && e<128 ? e : -1);
71 static void removepreload(void) {
72 const char *myself, *found;
73 char *newval, *preload;
74 int lpreload, lmyself, before, after;
76 preload= getenv(PRELOAD_VAR);
77 myself= getenv(AUTHBINDLIB_VAR);
78 if (!myself || !preload) return;
80 lpreload= strlen(preload);
81 lmyself= strlen(myself);
83 if (lmyself < 1 || lpreload<lmyself) return;
84 if (lpreload==lmyself) {
85 if (!strcmp(preload,myself)) unsetenv(PRELOAD_VAR);
88 if (!memcmp(preload,myself,lmyself) && preload[lmyself]==':') {
89 before= 0; after= lpreload-(lmyself+1);
90 } else if (!memcmp(preload+lpreload-lmyself,myself,lmyself) &&
91 preload[lpreload-(lmyself+1)]==':') {
92 before= lpreload-(lmyself+1); after= 0;
94 if (lpreload<lmyself+2) return;
97 found= strstr(found,myself); if (!found) return;
98 if (found > preload+lpreload-(lmyself+1)) return;
99 if (found[-1]==':' && found[lmyself]==':') break;
102 before= found-preload;
103 after= lpreload-(before+lmyself+1);
105 newval= malloc(before+after+1);
107 memcpy(newval,preload,before);
108 strcpy(newval+before,preload+lpreload-after);
109 if (setenv(PRELOAD_VAR,newval,1)) return;
112 strcpy(preload+before,preload+lpreload-after);
121 /* If AUTHBIND_LEVELS is
122 * unset => always strip from preload
123 * set and starts with `y' => never strip from preload, keep AUTHBIND_LEVELS
124 * set to integer > 1 => do not strip now, subtract one from AUTHBIND_LEVELS
125 * set to integer 1 => do not strip now, unset AUTHBIND_LEVELS
126 * set to empty string or 0 => strip now, unset AUTHBIND_LEVELS
128 levels= getenv(AUTHBIND_LEVELS_VAR);
130 if (levels[0]=='y') return 0;
131 levelno= atoi(levels);
134 if (levelno > 0) sprintf(levels,"%d",levelno);
135 else unsetenv(AUTHBIND_LEVELS_VAR);
138 unsetenv(AUTHBIND_LEVELS_VAR);
144 int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
146 char portarg[5], addrarg[9];
149 if (addr->sa_family != AF_INET || addrlen != sizeof(struct sockaddr_in) ||
150 !geteuid() || ((struct sockaddr_in*)addr)->sin_port == 0 ||
151 ntohs(((struct sockaddr_in*)addr)->sin_port) >= IPPORT_RESERVED/2)
152 return old_bind(fd,addr,addrlen);
154 sprintf(addrarg,"%08lx",
155 ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL);
156 sprintf(portarg,"%04x",
157 ((unsigned int)(((struct sockaddr_in*)addr)->sin_port))&0x0ffff);
159 child= fork(); if (child==-1) return -1;
162 if (dup2(fd,0)) exiterrno(errno);
164 execl(HELPER,HELPER,addrarg,portarg,(char*)0);
166 STDERRSTR_CONST("libauthbind: possible installation problem - "
167 "could not invoke " HELPER " (");
168 STDERRSTR_STRING(rcsid);
169 STDERRSTR_CONST(")\n");
173 rchild= waitpid(child,&status,0);
174 if (rchild==-1) return -1;
175 if (rchild!=child) { errno= ECHILD; return -1; }
177 if (WIFEXITED(status)) {
178 if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; }