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 #include <sys/socket.h>
38 #include <arpa/inet.h>
40 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
41 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
43 typedef void anyfn_type(void);
45 static anyfn_type *find_any(const char *name) {
46 static const char *dlerr;
49 kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
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 #define socket_args int domain, int type, int protocol
61 #define bind_args int fd, const struct sockaddr *addr, socklen_t addrlen
63 X(socket, (domain,type,protocol)) \
64 X(bind, (fd,addr,addrlen))
66 #define DEF_OLD(fn,args) \
67 typedef int fn##_fn_type(fn##_args); \
68 static int find_##fn(fn##_args); \
69 static fn##_fn_type find_##fn, *old_##fn=find_##fn; \
70 static int find_##fn(fn##_args) { \
72 anyfn= find_any(#fn); if (!anyfn) return -1; \
73 old_##fn= (fn##_fn_type*)anyfn; \
74 return old_##fn args; \
79 #define WRAP(fn) int fn(fn##_args)
84 struct sockaddr_in v4;
85 struct sockaddr_in6 v6;
88 static fdinfo **table;
91 static fdinfo *lookup(int fd) {
92 if (fd>=tablesz) return 0;
96 #define ADDRPORTSTRLEN (INET6_ADDRSTRLEN+1+5) /* not including nul */
98 static int addrport2str(char buf[ADDRPORTSTRLEN+1],
99 const struct sockaddr *addr, socklen_t addrlen) {
100 const void *addrv=addr;
102 const struct sockaddr_in *sin;
103 const struct sockaddr_in6 *sin6;
106 switch (addr->sa_family) {
107 case AF_INET: sin =addrv; el=sizeof(*sin ); iav=&sin ->sin_addr ; port=sin ->sin_port ; break;
108 case AF_INET6: sin6=addrv; el=sizeof(*sin6); iav=&sin6->sin6_addr; port=sin6->sin6_port; break;
109 default: errno=ESRCH; return -1;
111 //fprintf(stderr,"af=%lu el=%lu addrlen=%lu\n",
112 // (unsigned long)addr->sa_family,
113 // (unsigned long)el,
114 // (unsigned long)addrlen);
115 if (addrlen!=el) { errno=EINVAL; return -1; }
117 if (!inet_ntop(addr->sa_family,iav,p,INET6_ADDRSTRLEN)) return -1;
119 sprintf(p,",%u",(unsigned)ntohs(port));
124 if (!((domain==AF_INET || domain==AF_INET6) &&
126 return old_socket(domain,type,protocol);
127 int fd=socket(AF_UNIX,SOCK_DGRAM,0);
131 table=realloc(table,newsz*sizeof(*table));
132 if (!table) goto fail;
133 while (tablesz<newsz) table[tablesz++]=0;
136 table[fd]=malloc(sizeof(*table[fd]));
137 if (!table[fd]) goto fail;
138 table[fd]->af=domain;
139 table[fd]->bound.v4.sin_family=0;
148 fdinfo *ent=lookup(fd);
149 if (!ent) return old_bind(fd,addr,addrlen);
150 const char *dir = getenv("UDP_PRELOAD_DIR");
151 if (!dir) { errno=ECHILD; return -1; }
152 struct sockaddr_un sun;
153 memset(&sun,0,sizeof(sun));
154 sun.sun_family=AF_UNIX;
155 int dl = strlen(dir);
156 if (dl + 1 + ADDRPORTSTRLEN + 1 > sizeof(sun.sun_path)) {
157 errno=ENAMETOOLONG; return -1;
159 strcpy(sun.sun_path,dir);
160 char *p=sun.sun_path+dl;
162 if (addrport2str(p,addr,addrlen)) return -1;
163 //fprintf(stderr,"binding %s\n",sun.sun_path);
164 if (unlink(sun.sun_path) && errno!=ENOENT) return -1;
165 return old_bind(fd,(const void*)&sun,sizeof(sun));
168 //udp (test/tmp/outside.conf:19): setsockopt(,IPV6_V6ONLY,&1,): Operation not supported