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 bind_args int fd, const struct sockaddr *addr, socklen_t addrlen
59 X(socket, (domain,type,protocol)) \
60 X(bind, (fd,addr,addrlen))
62 #define DEF_OLD(fn,args) \
63 typedef int fn##_fn_type(fn##_args); \
64 static int find_##fn(fn##_args); \
65 static fn##_fn_type find_##fn, *old_##fn=find_##fn; \
66 static int find_##fn(fn##_args) { \
68 anyfn= find_any(#fn); if (!anyfn) return -1; \
69 old_##fn= (fn##_fn_type*)anyfn; \
70 return old_##fn args; \
75 #define WRAP(fn) int fn(fn##_args)
80 struct sockaddr_in v4;
81 struct sockaddr_in6 v6;
84 static fdinfo **table;
87 static fdinfo *lookup(int fd) {
88 if (fd>=tablesz) return 0;
92 static int chkaddr(fdinfo *ent,
93 const struct sockaddr *addr, socklen_t addrlen) {
94 if (addr->sa_family!=ent->af) { errno=EAFNOSUPPORT; return -1; }
96 switch (addr->sa_family) {
97 case AF_INET: expectlen=sizeof(ent->bound.v4); break;
98 case AF_INET6: expectlen=sizeof(ent->bound.v6); break;
101 if (addrlen!=expectlen) { errno=EINVAL; return -1; }
106 if (!((domain==AF_INET || domain==AF_INET6) &&
108 return old_socket(domain,type,protocol);
109 int fd=socket(AF_UNIX,SOCK_DGRAM,0);
113 table=realloc(table,newsz*sizeof(*table));
114 if (!table) goto fail;
115 while (tablesz<newsz) table[tablesz++]=0;
118 table[fd]=malloc(sizeof(*table[fd]));
119 if (!table[fd]) goto fail;
120 table[fd]->af=domain;
121 table[fd]->bound.v4.sin_family=0;
130 fdinfo *ent=lookup(fd);
131 if (!ent) return bind(fd,addr,addrlen);
132 if (chkaddr(ent,addr,addrlen)) return -1;
133 memset(&ent->bound,0,sizeof(ent->bound));
134 memcpy(&ent->bound,addr,addrlen);