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$";
36 # define HELPER "/usr/local/lib/authbind/helper"
39 #define AUTHBIND_NESTED_VAR "AUTHBIND_NESTED"
41 typedef void anyfn_type(void);
42 typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen);
44 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
45 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
47 static int find_any(const char *name, anyfn_type **keep) {
48 static const char *dlerr;
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");
64 static bindfn_type find_bind, *old_bind= find_bind;
66 int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
68 if (find_any("bind",&anyfn)) return -1;
69 old_bind= (bindfn_type*)anyfn;
70 return old_bind(fd,addr,addrlen);
73 static int exiterrno(int e) {
74 _exit(e>0 && e<128 ? e : -1);
77 int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
79 char portarg[5], addrarg[9];
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);
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);
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);
99 child= fork(); if (child==-1) return -1;
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);
106 STDERRSTR_CONST("libauthbind: possible installation problem - "
107 "could not invoke " HELPER "\n");
111 rchild= waitpid(child,&status,0);
112 if (rchild==-1) return -1;
113 if (rchild!=child) { errno= ECHILD; return -1; }
115 if (WIFEXITED(status)) {
116 if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; }