r10374: Add HAVE_* defines (on command-line or in config.h file) for scons +
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket_wrapper / socket_wrapper.c
1 /* 
2    Socket wrapper library. Passes all socket communication over 
3    unix domain sockets if the environment variable SOCKET_WRAPPER_DIR 
4    is set.
5    Copyright (C) Jelmer Vernooij 2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #ifdef _SAMBA_BUILD_
23 #include "includes.h"
24 #undef SOCKET_WRAPPER
25 #include "system/network.h"
26 #include "system/filesys.h"
27 #else
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/socket.h>
31 #include <errno.h>
32 #include <sys/un.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <stdio.h>
39 #endif
40 #include "dlinklist.h"
41
42 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
43  * for now */
44 #define REWRITE_CALLS 
45
46 #ifdef REWRITE_CALLS
47 #define real_accept accept
48 #define real_connect connect
49 #define real_bind bind
50 #define real_getpeername getpeername
51 #define real_getsockname getsockname
52 #define real_getsockopt getsockopt
53 #define real_setsockopt setsockopt
54 #define real_recvfrom recvfrom
55 #define real_sendto sendto
56 #define real_socket socket
57 #define real_close close
58 #endif
59
60 /* we need to use a very terse format here as IRIX 6.4 silently
61    truncates names to 16 chars, so if we use a longer name then we
62    can't tell which port a packet came from with recvfrom() 
63    
64    with this format we have 8 chars left for the directory name
65 */
66 #define SOCKET_FORMAT "%u_%u"
67
68 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
69 {
70         struct sockaddr *ret = (struct sockaddr *)malloc(len);
71         memcpy(ret, data, len);
72         return ret;
73 }
74
75 struct socket_info
76 {
77         int fd;
78
79         int domain;
80         int type;
81         int protocol;
82         int bound;
83
84         char *path;
85         char *tmp_path;
86
87         struct sockaddr *myname;
88         socklen_t myname_len;
89
90         struct sockaddr *peername;
91         socklen_t peername_len;
92
93         struct socket_info *prev, *next;
94 };
95
96 static struct socket_info *sockets = NULL;
97
98
99 static const char *socket_wrapper_dir(void)
100 {
101         const char *s = getenv("SOCKET_WRAPPER_DIR");
102         if (s == NULL) {
103                 return NULL;
104         }
105         if (strncmp(s, "./", 2) == 0) {
106                 s += 2;
107         }
108         return s;
109 }
110
111 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
112 {
113         unsigned int prt;
114         const char *p;
115         int type;
116
117         if ((*len) < sizeof(struct sockaddr_in)) {
118                 return 0;
119         }
120
121         in->sin_family = AF_INET;
122         in->sin_port = htons(1025); /* Default to 1025 */
123         p = strrchr(un->sun_path, '/');
124         if (p) p++; else p = un->sun_path;
125
126         if (sscanf(p, SOCKET_FORMAT, &type, &prt) == 2) {
127                 in->sin_port = htons(prt);
128         }
129         in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
130         *len = sizeof(struct sockaddr_in);
131         return 0;
132 }
133
134 static int convert_in_un(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un)
135 {
136         int type = si->type;
137         uint16_t prt = ntohs(in->sin_port);
138         if (prt == 0) {
139                 struct stat st;
140                 /* handle auto-allocation of ephemeral ports */
141                 prt = 5000;
142                 do {
143                         snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
144                                  socket_wrapper_dir(), type, ++prt);
145                 } while (stat(un->sun_path, &st) == 0 && prt < 10000);
146                 ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
147         } 
148         snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
149                  socket_wrapper_dir(), type, prt);
150         return 0;
151 }
152
153 static struct socket_info *find_socket_info(int fd)
154 {
155         struct socket_info *i;
156         for (i = sockets; i; i = i->next) {
157                 if (i->fd == fd) 
158                         return i;
159         }
160
161         return NULL;
162 }
163
164 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, 
165                                          struct sockaddr_un *out_addr)
166 {
167         if (!out_addr)
168                 return 0;
169
170         out_addr->sun_family = AF_UNIX;
171
172         switch (in_addr->sa_family) {
173         case AF_INET:
174                 return convert_in_un(si, (const struct sockaddr_in *)in_addr, out_addr);
175         case AF_UNIX:
176                 memcpy(out_addr, in_addr, sizeof(*out_addr));
177                 return 0;
178         default:
179                 break;
180         }
181         
182         errno = EAFNOSUPPORT;
183         return -1;
184 }
185
186 static int sockaddr_convert_from_un(const struct socket_info *si, 
187                                     const struct sockaddr_un *in_addr, 
188                                     socklen_t un_addrlen,
189                                     int family,
190                                     struct sockaddr *out_addr,
191                                     socklen_t *out_len)
192 {
193         if (out_addr == NULL || out_len == NULL) 
194                 return 0;
195
196         if (un_addrlen == 0) {
197                 *out_len = 0;
198                 return 0;
199         }
200
201         switch (family) {
202         case AF_INET:
203                 return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, out_len);
204         case AF_UNIX:
205                 memcpy(out_addr, in_addr, sizeof(*in_addr));
206                 *out_len = sizeof(*in_addr);
207                 return 0;
208         default:
209                 break;
210         }
211
212         errno = EAFNOSUPPORT;
213         return -1;
214 }
215
216 int swrap_socket(int domain, int type, int protocol)
217 {
218         struct socket_info *si;
219         int fd;
220
221         if (!socket_wrapper_dir()) {
222                 return real_socket(domain, type, protocol);
223         }
224         
225         fd = real_socket(AF_UNIX, type, 0);
226
227         if (fd == -1) return -1;
228
229         si = calloc(1, sizeof(struct socket_info));
230
231         si->domain = domain;
232         si->type = type;
233         si->protocol = protocol;
234         si->fd = fd;
235
236         DLIST_ADD(sockets, si);
237
238         return si->fd;
239 }
240
241 int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
242 {
243         struct socket_info *parent_si, *child_si;
244         int fd;
245         socklen_t un_addrlen = sizeof(struct sockaddr_un);
246         struct sockaddr_un un_addr;
247         int ret;
248
249         parent_si = find_socket_info(s);
250         if (!parent_si) {
251                 return real_accept(s, addr, addrlen);
252         }
253
254         memset(&un_addr, 0, sizeof(un_addr));
255
256         ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
257         if (ret == -1) return ret;
258
259         fd = ret;
260
261         ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
262                                        parent_si->domain, addr, addrlen);
263         if (ret == -1) return ret;
264
265         child_si = malloc(sizeof(struct socket_info));
266         memset(child_si, 0, sizeof(*child_si));
267
268         child_si->fd = fd;
269         child_si->bound = 1;
270
271         child_si->myname_len = parent_si->myname_len;
272         child_si->myname = sockaddr_dup(parent_si->myname, parent_si->myname_len);
273
274         child_si->peername_len = *addrlen;
275         child_si->peername = sockaddr_dup(addr, *addrlen);
276
277         DLIST_ADD(sockets, child_si);
278
279         return fd;
280 }
281
282 /* using sendto() or connect() on an unbound socket would give the
283    recipient no way to reply, as unlike UDP and TCP, a unix domain
284    socket can't auto-assign emphemeral port numbers, so we need to
285    assign it here */
286 static int swrap_auto_bind(struct socket_info *si)
287 {
288         struct sockaddr_un un_addr;
289         struct sockaddr_in in;
290         int i;
291         
292         un_addr.sun_family = AF_UNIX;
293         
294         for (i=0;i<1000;i++) {
295                 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
296                          "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
297                          SOCK_DGRAM, i + 10000);
298                 if (bind(si->fd, (struct sockaddr *)&un_addr, 
299                          sizeof(un_addr)) == 0) {
300                         si->tmp_path = strdup(un_addr.sun_path);
301                         si->bound = 1;
302                         break;
303                 }
304         }
305         if (i == 1000) {
306                 return -1;
307         }
308         
309         memset(&in, 0, sizeof(in));
310         in.sin_family = AF_INET;
311         in.sin_port   = htons(i);
312         in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
313         
314         si->myname_len = sizeof(in);
315         si->myname = sockaddr_dup(&in, si->myname_len);
316         si->bound = 1;
317         return 0;
318 }
319
320
321 int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
322 {
323         int ret;
324         struct sockaddr_un un_addr;
325         struct socket_info *si = find_socket_info(s);
326
327         if (!si) {
328                 return real_connect(s, serv_addr, addrlen);
329         }
330
331         /* only allow pseudo loopback connections */
332         if (serv_addr->sa_family == AF_INET &&
333                 ((const struct sockaddr_in *)serv_addr)->sin_addr.s_addr != 
334             htonl(INADDR_LOOPBACK)) {
335                 errno = ENETUNREACH;
336                 return -1;
337         }
338
339         if (si->bound == 0 && si->domain != AF_UNIX) {
340                 ret = swrap_auto_bind(si);
341                 if (ret == -1) return -1;
342         }
343
344         ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr);
345         if (ret == -1) return -1;
346
347         ret = real_connect(s, (struct sockaddr *)&un_addr, 
348                            sizeof(struct sockaddr_un));
349
350         if (ret == 0) {
351                 si->peername_len = addrlen;
352                 si->peername = sockaddr_dup(serv_addr, addrlen);
353         }
354
355         return ret;
356 }
357
358 int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
359 {
360         int ret;
361         struct sockaddr_un un_addr;
362         struct socket_info *si = find_socket_info(s);
363
364         if (!si) {
365                 return real_bind(s, myaddr, addrlen);
366         }
367
368         si->myname_len = addrlen;
369         si->myname = sockaddr_dup(myaddr, addrlen);
370
371         if (myaddr->sa_family == AF_INET &&
372             ((const struct sockaddr_in *)myaddr)->sin_addr.s_addr == 0) {
373                 ((struct sockaddr_in *)si->myname)->sin_addr.s_addr = 
374                         htonl(INADDR_LOOPBACK);
375         }
376         ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr);
377         if (ret == -1) return -1;
378
379         unlink(un_addr.sun_path);
380
381         ret = real_bind(s, (struct sockaddr *)&un_addr,
382                         sizeof(struct sockaddr_un));
383
384         if (ret == 0) {
385                 si->bound = 1;
386         }
387
388         return ret;
389 }
390
391 int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
392 {
393         struct socket_info *si = find_socket_info(s);
394
395         if (!si) {
396                 return real_getpeername(s, name, addrlen);
397         }
398
399         if (!si->peername) 
400         {
401                 errno = ENOTCONN;
402                 return -1;
403         }
404
405         memcpy(name, si->peername, si->peername_len);
406         *addrlen = si->peername_len;
407
408         return 0;
409 }
410
411 int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
412 {
413         struct socket_info *si = find_socket_info(s);
414
415         if (!si) {
416                 return real_getsockname(s, name, addrlen);
417         }
418
419         memcpy(name, si->myname, si->myname_len);
420         *addrlen = si->myname_len;
421
422         return 0;
423 }
424
425 int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
426 {
427         struct socket_info *si = find_socket_info(s);
428
429         if (!si) {
430                 return real_getsockopt(s, level, optname, optval, optlen);
431         }
432
433         if (level == SOL_SOCKET) {
434                 return real_getsockopt(s, level, optname, optval, optlen);
435         } 
436
437         switch (si->domain) {
438         case AF_UNIX:
439                 return real_getsockopt(s, level, optname, optval, optlen);
440         default:
441                 errno = ENOPROTOOPT;
442                 return -1;
443         }
444 }
445
446 int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *optval, socklen_t optlen)
447 {
448         struct socket_info *si = find_socket_info(s);
449
450         if (!si) {
451                 return real_setsockopt(s, level, optname, optval, optlen);
452         }
453
454         if (level == SOL_SOCKET) {
455                 return real_setsockopt(s, level, optname, optval, optlen);
456         }
457
458         switch (si->domain) {
459         case AF_UNIX:
460                 return real_setsockopt(s, level, optname, optval, optlen);
461         case AF_INET:
462                 /* Silence some warnings */
463 #ifdef TCP_NODELAY
464                 if (optname == TCP_NODELAY) 
465                         return 0;
466 #endif
467         default:
468                 errno = ENOPROTOOPT;
469                 return -1;
470         }
471 }
472
473 ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
474 {
475         struct sockaddr_un un_addr;
476         socklen_t un_addrlen = sizeof(un_addr);
477         int ret;
478         struct socket_info *si = find_socket_info(s);
479
480         if (!si) {
481                 return real_recvfrom(s, buf, len, flags, from, fromlen);
482         }
483
484         /* irix 6.4 forgets to null terminate the sun_path string :-( */
485         memset(&un_addr, 0, sizeof(un_addr));
486         ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
487         if (ret == -1) 
488                 return ret;
489
490         if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
491                                      si->domain, from, fromlen) == -1) {
492                 return -1;
493         }
494         
495         return ret;
496 }
497
498
499 ssize_t swrap_sendto(int  s,  const  void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
500 {
501         struct sockaddr_un un_addr;
502         int ret;
503         struct socket_info *si = find_socket_info(s);
504
505         if (!si) {
506                 return real_sendto(s, buf, len, flags, to, tolen);
507         }
508
509         if (si->bound == 0 && si->domain != AF_UNIX) {
510                 ret = swrap_auto_bind(si);
511                 if (ret == -1) return -1;
512         }
513
514         ret = sockaddr_convert_to_un(si, to, tolen, &un_addr);
515         if (ret == -1) return -1;
516
517         ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
518
519         return ret;
520 }
521
522 int swrap_close(int fd)
523 {
524         struct socket_info *si = find_socket_info(fd);
525
526         if (si) {
527                 DLIST_REMOVE(sockets, si);
528
529                 free(si->path);
530                 free(si->myname);
531                 free(si->peername);
532                 if (si->tmp_path) {
533                         unlink(si->tmp_path);
534                         free(si->tmp_path);
535                 }
536                 free(si);
537         }
538
539         return real_close(fd);
540 }