d0d08d22b9364a1b08ea752cc7585d3743ecb092
[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 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
99 {
100         unsigned int prt;
101         const char *p;
102         int type;
103
104         if ((*len) < sizeof(struct sockaddr_in)) {
105                 return 0;
106         }
107
108         in->sin_family = AF_INET;
109         in->sin_port = htons(1025); /* Default to 1025 */
110         p = strrchr(un->sun_path, '/');
111         if (p) p++; else p = un->sun_path;
112
113         if (sscanf(p, SOCKET_FORMAT, &type, &prt) == 2) {
114                 in->sin_port = htons(prt);
115         }
116         in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
117         *len = sizeof(struct sockaddr_in);
118         return 0;
119 }
120
121 static int convert_in_un(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un)
122 {
123         int type = si->type;
124         uint16_t prt = ntohs(in->sin_port);
125         if (prt == 0) {
126                 struct stat st;
127                 /* handle auto-allocation of ephemeral ports */
128                 prt = 5000;
129                 do {
130                         snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
131                                  getenv("SOCKET_WRAPPER_DIR"), type, ++prt);
132                 } while (stat(un->sun_path, &st) == 0 && prt < 10000);
133                 ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
134         } 
135         snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
136                  getenv("SOCKET_WRAPPER_DIR"), type, prt);
137         return 0;
138 }
139
140 static struct socket_info *find_socket_info(int fd)
141 {
142         struct socket_info *i;
143         for (i = sockets; i; i = i->next) {
144                 if (i->fd == fd) 
145                         return i;
146         }
147
148         return NULL;
149 }
150
151 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, 
152                                          struct sockaddr_un *out_addr)
153 {
154         if (!out_addr)
155                 return 0;
156
157         out_addr->sun_family = AF_UNIX;
158
159         switch (in_addr->sa_family) {
160         case AF_INET:
161                 return convert_in_un(si, (const struct sockaddr_in *)in_addr, out_addr);
162         case AF_UNIX:
163                 memcpy(out_addr, in_addr, sizeof(*out_addr));
164                 return 0;
165         default:
166                 break;
167         }
168         
169         errno = EAFNOSUPPORT;
170         return -1;
171 }
172
173 static int sockaddr_convert_from_un(const struct socket_info *si, 
174                                     const struct sockaddr_un *in_addr, 
175                                     socklen_t un_addrlen,
176                                     int family,
177                                     struct sockaddr *out_addr,
178                                     socklen_t *out_len)
179 {
180         if (out_addr == NULL || out_len == NULL) 
181                 return 0;
182
183         if (un_addrlen == 0) {
184                 *out_len = 0;
185                 return 0;
186         }
187
188         switch (family) {
189         case AF_INET:
190                 return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, out_len);
191         case AF_UNIX:
192                 memcpy(out_addr, in_addr, sizeof(*in_addr));
193                 *out_len = sizeof(*in_addr);
194                 return 0;
195         default:
196                 break;
197         }
198
199         errno = EAFNOSUPPORT;
200         return -1;
201 }
202
203 int swrap_socket(int domain, int type, int protocol)
204 {
205         struct socket_info *si;
206         int fd;
207
208         if (!getenv("SOCKET_WRAPPER_DIR")) {
209                 return real_socket(domain, type, protocol);
210         }
211         
212         fd = real_socket(AF_UNIX, type, 0);
213
214         if (fd == -1) return -1;
215
216         si = calloc(1, sizeof(struct socket_info));
217
218         si->domain = domain;
219         si->type = type;
220         si->protocol = protocol;
221         si->fd = fd;
222
223         DLIST_ADD(sockets, si);
224
225         return si->fd;
226 }
227
228 int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
229 {
230         struct socket_info *parent_si, *child_si;
231         int fd;
232         socklen_t un_addrlen = sizeof(struct sockaddr_un);
233         struct sockaddr_un un_addr;
234         int ret;
235
236         parent_si = find_socket_info(s);
237         if (!parent_si) {
238                 return real_accept(s, addr, addrlen);
239         }
240
241         memset(&un_addr, 0, sizeof(un_addr));
242
243         ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
244         if (ret == -1) return ret;
245
246         fd = ret;
247
248         ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
249                                        parent_si->domain, addr, addrlen);
250         if (ret == -1) return ret;
251
252         child_si = malloc(sizeof(struct socket_info));
253         memset(child_si, 0, sizeof(*child_si));
254
255         child_si->fd = fd;
256         child_si->bound = 1;
257
258         child_si->myname_len = parent_si->myname_len;
259         child_si->myname = sockaddr_dup(parent_si->myname, parent_si->myname_len);
260
261         child_si->peername_len = *addrlen;
262         child_si->peername = sockaddr_dup(addr, *addrlen);
263
264         DLIST_ADD(sockets, child_si);
265
266         return fd;
267 }
268
269 /* using sendto() or connect() on an unbound socket would give the
270    recipient no way to reply, as unlike UDP and TCP, a unix domain
271    socket can't auto-assign emphemeral port numbers, so we need to
272    assign it here */
273 static int swrap_auto_bind(struct socket_info *si)
274 {
275         struct sockaddr_un un_addr;
276         struct sockaddr_in in;
277         int i;
278         
279         un_addr.sun_family = AF_UNIX;
280         
281         for (i=0;i<1000;i++) {
282                 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
283                          "%s/"SOCKET_FORMAT, getenv("SOCKET_WRAPPER_DIR"), 
284                          SOCK_DGRAM, i + 10000);
285                 if (bind(si->fd, (struct sockaddr *)&un_addr, 
286                          sizeof(un_addr)) == 0) {
287                         si->tmp_path = strdup(un_addr.sun_path);
288                         si->bound = 1;
289                         break;
290                 }
291         }
292         if (i == 1000) {
293                 return -1;
294         }
295         
296         memset(&in, 0, sizeof(in));
297         in.sin_family = AF_INET;
298         in.sin_port   = htons(i);
299         in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
300         
301         si->myname_len = sizeof(in);
302         si->myname = sockaddr_dup(&in, si->myname_len);
303         si->bound = 1;
304         return 0;
305 }
306
307
308 int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
309 {
310         int ret;
311         struct sockaddr_un un_addr;
312         struct socket_info *si = find_socket_info(s);
313
314         if (!si) {
315                 return real_connect(s, serv_addr, addrlen);
316         }
317
318         /* only allow pseudo loopback connections */
319         if (serv_addr->sa_family == AF_INET &&
320                 ((const struct sockaddr_in *)serv_addr)->sin_addr.s_addr != 
321             htonl(INADDR_LOOPBACK)) {
322                 errno = ENETUNREACH;
323                 return -1;
324         }
325
326         if (si->bound == 0 && si->domain != AF_UNIX) {
327                 ret = swrap_auto_bind(si);
328                 if (ret == -1) return -1;
329         }
330
331         ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr);
332         if (ret == -1) return -1;
333
334         ret = real_connect(s, (struct sockaddr *)&un_addr, 
335                            sizeof(struct sockaddr_un));
336
337         if (ret == 0) {
338                 si->peername_len = addrlen;
339                 si->peername = sockaddr_dup(serv_addr, addrlen);
340         }
341
342         return ret;
343 }
344
345 int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
346 {
347         int ret;
348         struct sockaddr_un un_addr;
349         struct socket_info *si = find_socket_info(s);
350
351         if (!si) {
352                 return real_bind(s, myaddr, addrlen);
353         }
354
355         si->myname_len = addrlen;
356         si->myname = sockaddr_dup(myaddr, addrlen);
357
358         if (myaddr->sa_family == AF_INET &&
359             ((const struct sockaddr_in *)myaddr)->sin_addr.s_addr == 0) {
360                 ((struct sockaddr_in *)si->myname)->sin_addr.s_addr = 
361                         htonl(INADDR_LOOPBACK);
362         }
363         ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr);
364         if (ret == -1) return -1;
365
366         unlink(un_addr.sun_path);
367
368         ret = real_bind(s, (struct sockaddr *)&un_addr,
369                         sizeof(struct sockaddr_un));
370
371         if (ret == 0) {
372                 si->bound = 1;
373         }
374
375         return ret;
376 }
377
378 int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
379 {
380         struct socket_info *si = find_socket_info(s);
381
382         if (!si) {
383                 return real_getpeername(s, name, addrlen);
384         }
385
386         if (!si->peername) 
387         {
388                 errno = ENOTCONN;
389                 return -1;
390         }
391
392         memcpy(name, si->peername, si->peername_len);
393         *addrlen = si->peername_len;
394
395         return 0;
396 }
397
398 int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
399 {
400         struct socket_info *si = find_socket_info(s);
401
402         if (!si) {
403                 return real_getsockname(s, name, addrlen);
404         }
405
406         memcpy(name, si->myname, si->myname_len);
407         *addrlen = si->myname_len;
408
409         return 0;
410 }
411
412 int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
413 {
414         struct socket_info *si = find_socket_info(s);
415
416         if (!si) {
417                 return real_getsockopt(s, level, optname, optval, optlen);
418         }
419
420         if (level == SOL_SOCKET) {
421                 return real_getsockopt(s, level, optname, optval, optlen);
422         } 
423
424         switch (si->domain) {
425         case AF_UNIX:
426                 return real_getsockopt(s, level, optname, optval, optlen);
427         default:
428                 errno = ENOPROTOOPT;
429                 return -1;
430         }
431 }
432
433 int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *optval, socklen_t optlen)
434 {
435         struct socket_info *si = find_socket_info(s);
436
437         if (!si) {
438                 return real_setsockopt(s, level, optname, optval, optlen);
439         }
440
441         if (level == SOL_SOCKET) {
442                 return real_setsockopt(s, level, optname, optval, optlen);
443         }
444
445         switch (si->domain) {
446         case AF_UNIX:
447                 return real_setsockopt(s, level, optname, optval, optlen);
448         case AF_INET:
449                 /* Silence some warnings */
450 #ifdef TCP_NODELAY
451                 if (optname == TCP_NODELAY) 
452                         return 0;
453 #endif
454         default:
455                 errno = ENOPROTOOPT;
456                 return -1;
457         }
458 }
459
460 ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
461 {
462         struct sockaddr_un un_addr;
463         socklen_t un_addrlen = sizeof(un_addr);
464         int ret;
465         struct socket_info *si = find_socket_info(s);
466
467         if (!si) {
468                 return real_recvfrom(s, buf, len, flags, from, fromlen);
469         }
470
471         /* irix 6.4 forgets to null terminate the sun_path string :-( */
472         memset(&un_addr, 0, sizeof(un_addr));
473         ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
474         if (ret == -1) 
475                 return ret;
476
477         if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
478                                      si->domain, from, fromlen) == -1) {
479                 return -1;
480         }
481         
482         return ret;
483 }
484
485
486 ssize_t swrap_sendto(int  s,  const  void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
487 {
488         struct sockaddr_un un_addr;
489         int ret;
490         struct socket_info *si = find_socket_info(s);
491
492         if (!si) {
493                 return real_sendto(s, buf, len, flags, to, tolen);
494         }
495
496         if (si->bound == 0 && si->domain != AF_UNIX) {
497                 ret = swrap_auto_bind(si);
498                 if (ret == -1) return -1;
499         }
500
501         ret = sockaddr_convert_to_un(si, to, tolen, &un_addr);
502         if (ret == -1) return -1;
503
504         ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
505
506         return ret;
507 }
508
509 int swrap_close(int fd)
510 {
511         struct socket_info *si = find_socket_info(fd);
512
513         if (si) {
514                 DLIST_REMOVE(sockets, si);
515
516                 free(si->path);
517                 free(si->myname);
518                 free(si->peername);
519                 if (si->tmp_path) {
520                         unlink(si->tmp_path);
521                         free(si->tmp_path);
522                 }
523                 free(si);
524         }
525
526         return real_close(fd);
527 }