Fix Coverity ID 871 -- do not dereference "sp" before checking for NULL
[nivanova/samba-autobuild/.git] / source4 / lib / socket / socket_ip.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Socket IPv4/IPv6 functions
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Tridgell 2004-2005
8    Copyright (C) Jelmer Vernooij 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "lib/socket/socket.h"
27 #include "system/network.h"
28
29 static NTSTATUS ipv4_init(struct socket_context *sock)
30 {
31         int type;
32
33         switch (sock->type) {
34         case SOCKET_TYPE_STREAM:
35                 type = SOCK_STREAM;
36                 break;
37         case SOCKET_TYPE_DGRAM:
38                 type = SOCK_DGRAM;
39                 break;
40         default:
41                 return NT_STATUS_INVALID_PARAMETER;
42         }
43
44         sock->fd = socket(PF_INET, type, 0);
45         if (sock->fd == -1) {
46                 return map_nt_error_from_unix(errno);
47         }
48
49         sock->backend_name = "ipv4";
50         sock->family = AF_INET;
51
52         return NT_STATUS_OK;
53 }
54
55 static void ip_close(struct socket_context *sock)
56 {
57         close(sock->fd);
58 }
59
60 static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
61 {
62         int error=0, ret;
63         socklen_t len = sizeof(error);
64
65         /* check for any errors that may have occurred - this is needed
66            for non-blocking connect */
67         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
68         if (ret == -1) {
69                 return map_nt_error_from_unix(errno);
70         }
71         if (error != 0) {
72                 return map_nt_error_from_unix(error);
73         }
74
75         if (!(flags & SOCKET_FLAG_BLOCK)) {
76                 ret = set_blocking(sock->fd, false);
77                 if (ret == -1) {
78                         return map_nt_error_from_unix(errno);
79                 }
80         }
81
82         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
83
84         return NT_STATUS_OK;
85 }
86
87
88 static NTSTATUS ipv4_connect(struct socket_context *sock,
89                              const struct socket_address *my_address, 
90                              const struct socket_address *srv_address,
91                              uint32_t flags)
92 {
93         struct sockaddr_in srv_addr;
94         struct in_addr my_ip;
95         struct in_addr srv_ip;
96         int ret;
97
98         if (my_address && my_address->sockaddr) {
99                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
100                 if (ret == -1) {
101                         return map_nt_error_from_unix(errno);
102                 }
103         } else if (my_address) {
104                 my_ip = interpret_addr2(my_address->addr);
105                 
106                 if (my_ip.s_addr != 0 || my_address->port != 0) {
107                         struct sockaddr_in my_addr;
108                         ZERO_STRUCT(my_addr);
109 #ifdef HAVE_SOCK_SIN_LEN
110                         my_addr.sin_len         = sizeof(my_addr);
111 #endif
112                         my_addr.sin_addr.s_addr = my_ip.s_addr;
113                         my_addr.sin_port        = htons(my_address->port);
114                         my_addr.sin_family      = PF_INET;
115                         
116                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
117                         if (ret == -1) {
118                                 return map_nt_error_from_unix(errno);
119                         }
120                 }
121         }
122
123         if (srv_address->sockaddr) {
124                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
125                 if (ret == -1) {
126                         return map_nt_error_from_unix(errno);
127                 }
128         } else {
129                 srv_ip = interpret_addr2(srv_address->addr);
130                 if (!srv_ip.s_addr) {
131                         return NT_STATUS_BAD_NETWORK_NAME;
132                 }
133
134                 SMB_ASSERT(srv_address->port != 0);
135                 
136                 ZERO_STRUCT(srv_addr);
137 #ifdef HAVE_SOCK_SIN_LEN
138                 srv_addr.sin_len        = sizeof(srv_addr);
139 #endif
140                 srv_addr.sin_addr.s_addr= srv_ip.s_addr;
141                 srv_addr.sin_port       = htons(srv_address->port);
142                 srv_addr.sin_family     = PF_INET;
143
144                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
145                 if (ret == -1) {
146                         return map_nt_error_from_unix(errno);
147                 }
148         }
149
150         return ip_connect_complete(sock, flags);
151 }
152
153
154 /*
155   note that for simplicity of the API, socket_listen() is also
156   use for DGRAM sockets, but in reality only a bind() is done
157 */
158 static NTSTATUS ipv4_listen(struct socket_context *sock,
159                             const struct socket_address *my_address, 
160                             int queue_size, uint32_t flags)
161 {
162         struct sockaddr_in my_addr;
163         struct in_addr ip_addr;
164         int ret;
165
166         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
167
168         if (my_address->sockaddr) {
169                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
170         } else {
171                 ip_addr = interpret_addr2(my_address->addr);
172                 
173                 ZERO_STRUCT(my_addr);
174 #ifdef HAVE_SOCK_SIN_LEN
175                 my_addr.sin_len         = sizeof(my_addr);
176 #endif
177                 my_addr.sin_addr.s_addr = ip_addr.s_addr;
178                 my_addr.sin_port        = htons(my_address->port);
179                 my_addr.sin_family      = PF_INET;
180                 
181                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
182         }
183
184         if (ret == -1) {
185                 return map_nt_error_from_unix(errno);
186         }
187
188         if (sock->type == SOCKET_TYPE_STREAM) {
189                 ret = listen(sock->fd, queue_size);
190                 if (ret == -1) {
191                         return map_nt_error_from_unix(errno);
192                 }
193         }
194
195         if (!(flags & SOCKET_FLAG_BLOCK)) {
196                 ret = set_blocking(sock->fd, false);
197                 if (ret == -1) {
198                         return map_nt_error_from_unix(errno);
199                 }
200         }
201
202         sock->state= SOCKET_STATE_SERVER_LISTEN;
203
204         return NT_STATUS_OK;
205 }
206
207 static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
208 {
209         struct sockaddr_in cli_addr;
210         socklen_t cli_addr_len = sizeof(cli_addr);
211         int new_fd;
212
213         if (sock->type != SOCKET_TYPE_STREAM) {
214                 return NT_STATUS_INVALID_PARAMETER;
215         }
216
217         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
218         if (new_fd == -1) {
219                 return map_nt_error_from_unix(errno);
220         }
221
222         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
223                 int ret = set_blocking(new_fd, false);
224                 if (ret == -1) {
225                         close(new_fd);
226                         return map_nt_error_from_unix(errno);
227                 }
228         }
229
230         /* TODO: we could add a 'accept_check' hook here
231          *       which get the black/white lists via socket_set_accept_filter()
232          *       or something like that
233          *       --metze
234          */
235
236         (*new_sock) = talloc(NULL, struct socket_context);
237         if (!(*new_sock)) {
238                 close(new_fd);
239                 return NT_STATUS_NO_MEMORY;
240         }
241
242         /* copy the socket_context */
243         (*new_sock)->type               = sock->type;
244         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
245         (*new_sock)->flags              = sock->flags;
246
247         (*new_sock)->fd                 = new_fd;
248
249         (*new_sock)->private_data       = NULL;
250         (*new_sock)->ops                = sock->ops;
251         (*new_sock)->backend_name       = sock->backend_name;
252
253         return NT_STATUS_OK;
254 }
255
256 static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 
257                               size_t wantlen, size_t *nread)
258 {
259         ssize_t gotlen;
260
261         *nread = 0;
262
263         gotlen = recv(sock->fd, buf, wantlen, 0);
264         if (gotlen == 0) {
265                 return NT_STATUS_END_OF_FILE;
266         } else if (gotlen == -1) {
267                 return map_nt_error_from_unix(errno);
268         }
269
270         *nread = gotlen;
271
272         return NT_STATUS_OK;
273 }
274
275
276 static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, 
277                               size_t wantlen, size_t *nread, 
278                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
279 {
280         ssize_t gotlen;
281         struct sockaddr_in *from_addr;
282         socklen_t from_len = sizeof(*from_addr);
283         struct socket_address *src;
284         char addrstring[INET_ADDRSTRLEN];
285         
286         src = talloc(addr_ctx, struct socket_address);
287         if (!src) {
288                 return NT_STATUS_NO_MEMORY;
289         }
290         
291         src->family = sock->backend_name;
292
293         from_addr = talloc(src, struct sockaddr_in);
294         if (!from_addr) {
295                 talloc_free(src);
296                 return NT_STATUS_NO_MEMORY;
297         }
298
299         src->sockaddr = (struct sockaddr *)from_addr;
300
301         *nread = 0;
302
303         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
304                           src->sockaddr, &from_len);
305         if (gotlen == 0) {
306                 talloc_free(src);
307                 return NT_STATUS_END_OF_FILE;
308         } else if (gotlen == -1) {
309                 talloc_free(src);
310                 return map_nt_error_from_unix(errno);
311         }
312
313         src->sockaddrlen = from_len;
314
315         if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring, 
316                          sizeof(addrstring)) == NULL) {
317                 talloc_free(src);
318                 return NT_STATUS_INTERNAL_ERROR;
319         }
320         src->addr = talloc_strdup(src, addrstring);
321         if (src->addr == NULL) {
322                 talloc_free(src);
323                 return NT_STATUS_NO_MEMORY;
324         }
325         src->port = ntohs(from_addr->sin_port);
326
327         *nread  = gotlen;
328         *_src   = src;
329         return NT_STATUS_OK;
330 }
331
332 static NTSTATUS ip_send(struct socket_context *sock, 
333                               const DATA_BLOB *blob, size_t *sendlen)
334 {
335         ssize_t len;
336
337         *sendlen = 0;
338
339         len = send(sock->fd, blob->data, blob->length, 0);
340         if (len == -1) {
341                 return map_nt_error_from_unix(errno);
342         }       
343
344         *sendlen = len;
345
346         return NT_STATUS_OK;
347 }
348
349 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
350                             const DATA_BLOB *blob, size_t *sendlen, 
351                             const struct socket_address *dest_addr)
352 {
353         ssize_t len;
354
355         if (dest_addr->sockaddr) {
356                 len = sendto(sock->fd, blob->data, blob->length, 0, 
357                              dest_addr->sockaddr, dest_addr->sockaddrlen);
358         } else {
359                 struct sockaddr_in srv_addr;
360                 struct in_addr addr;
361
362                 SMB_ASSERT(dest_addr->port != 0);
363                 
364                 ZERO_STRUCT(srv_addr);
365 #ifdef HAVE_SOCK_SIN_LEN
366                 srv_addr.sin_len         = sizeof(srv_addr);
367 #endif
368                 addr                     = interpret_addr2(dest_addr->addr);
369                 if (addr.s_addr == 0) {
370                         return NT_STATUS_HOST_UNREACHABLE;
371                 }
372                 srv_addr.sin_addr.s_addr = addr.s_addr;
373                 srv_addr.sin_port        = htons(dest_addr->port);
374                 srv_addr.sin_family      = PF_INET;
375                 
376                 *sendlen = 0;
377                 
378                 len = sendto(sock->fd, blob->data, blob->length, 0, 
379                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
380         }
381         if (len == -1) {
382                 return map_nt_error_from_unix(errno);
383         }       
384
385         *sendlen = len;
386
387         return NT_STATUS_OK;
388 }
389
390 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
391 {
392         set_socket_options(sock->fd, option);
393         return NT_STATUS_OK;
394 }
395
396 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
397 {
398         struct sockaddr_in peer_addr;
399         socklen_t len = sizeof(peer_addr);
400         struct hostent *he;
401         int ret;
402
403         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
404         if (ret == -1) {
405                 return NULL;
406         }
407
408         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
409         if (he == NULL) {
410                 return NULL;
411         }
412
413         return talloc_strdup(mem_ctx, he->h_name);
414 }
415
416 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
417 {
418         struct sockaddr_in *peer_addr;
419         socklen_t len = sizeof(*peer_addr);
420         struct socket_address *peer;
421         char addrstring[INET_ADDRSTRLEN];
422         int ret;
423         
424         peer = talloc(mem_ctx, struct socket_address);
425         if (!peer) {
426                 return NULL;
427         }
428         
429         peer->family = sock->backend_name;
430         peer_addr = talloc(peer, struct sockaddr_in);
431         if (!peer_addr) {
432                 talloc_free(peer);
433                 return NULL;
434         }
435
436         peer->sockaddr = (struct sockaddr *)peer_addr;
437
438         ret = getpeername(sock->fd, peer->sockaddr, &len);
439         if (ret == -1) {
440                 talloc_free(peer);
441                 return NULL;
442         }
443
444         peer->sockaddrlen = len;
445
446         if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
447                          sizeof(addrstring)) == NULL) {
448                 talloc_free(peer);
449                 return NULL;
450         }
451         peer->addr = talloc_strdup(peer, addrstring);
452         if (!peer->addr) {
453                 talloc_free(peer);
454                 return NULL;
455         }
456         peer->port = ntohs(peer_addr->sin_port);
457
458         return peer;
459 }
460
461 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
462 {
463         struct sockaddr_in *local_addr;
464         socklen_t len = sizeof(*local_addr);
465         struct socket_address *local;
466         char addrstring[INET_ADDRSTRLEN];
467         int ret;
468         
469         local = talloc(mem_ctx, struct socket_address);
470         if (!local) {
471                 return NULL;
472         }
473         
474         local->family = sock->backend_name;
475         local_addr = talloc(local, struct sockaddr_in);
476         if (!local_addr) {
477                 talloc_free(local);
478                 return NULL;
479         }
480
481         local->sockaddr = (struct sockaddr *)local_addr;
482
483         ret = getsockname(sock->fd, local->sockaddr, &len);
484         if (ret == -1) {
485                 talloc_free(local);
486                 return NULL;
487         }
488
489         local->sockaddrlen = len;
490
491         if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring, 
492                          sizeof(addrstring)) == NULL) {
493                 talloc_free(local);
494                 return NULL;
495         }
496         local->addr = talloc_strdup(local, addrstring);
497         if (!local->addr) {
498                 talloc_free(local);
499                 return NULL;
500         }
501         local->port = ntohs(local_addr->sin_port);
502
503         return local;
504 }
505 static int ip_get_fd(struct socket_context *sock)
506 {
507         return sock->fd;
508 }
509
510 static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
511 {
512         int value = 0;
513         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
514                 *npending = value;
515                 return NT_STATUS_OK;
516         }
517         return map_nt_error_from_unix(errno);
518 }
519
520 static const struct socket_ops ipv4_ops = {
521         .name                   = "ipv4",
522         .fn_init                = ipv4_init,
523         .fn_connect             = ipv4_connect,
524         .fn_connect_complete    = ip_connect_complete,
525         .fn_listen              = ipv4_listen,
526         .fn_accept              = ipv4_accept,
527         .fn_recv                = ip_recv,
528         .fn_recvfrom            = ipv4_recvfrom,
529         .fn_send                = ip_send,
530         .fn_sendto              = ipv4_sendto,
531         .fn_pending             = ip_pending,
532         .fn_close               = ip_close,
533
534         .fn_set_option          = ipv4_set_option,
535
536         .fn_get_peer_name       = ipv4_get_peer_name,
537         .fn_get_peer_addr       = ipv4_get_peer_addr,
538         .fn_get_my_addr         = ipv4_get_my_addr,
539
540         .fn_get_fd              = ip_get_fd
541 };
542
543 _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
544 {
545         return &ipv4_ops;
546 }
547
548 #if HAVE_IPV6
549
550 static struct in6_addr interpret_addr6(const char *name)
551 {
552         char addr[INET6_ADDRSTRLEN];
553         struct in6_addr dest6;
554         const char *sp = name;
555         char *p;
556         int ret;
557
558         if (sp == NULL) return in6addr_any;
559
560         p = strchr_m(sp, '%');
561
562         if (strcasecmp(sp, "localhost") == 0) {
563                 sp = "::1";
564         }
565
566         /*
567          * Cope with link-local.
568          * This is IP:v6:addr%ifname.
569          */
570
571         if (p && (p > sp) && (if_nametoindex(p+1) != 0)) {
572                 strlcpy(addr, sp,
573                         MIN(PTR_DIFF(p,sp)+1,
574                                 sizeof(addr)));
575                 sp = addr;
576         }
577
578         ret = inet_pton(AF_INET6, sp, &dest6);
579         if (ret > 0) {
580                 return dest6;
581         }
582
583         return in6addr_any;
584 }
585
586 static NTSTATUS ipv6_init(struct socket_context *sock)
587 {
588         int type;
589
590         switch (sock->type) {
591         case SOCKET_TYPE_STREAM:
592                 type = SOCK_STREAM;
593                 break;
594         case SOCKET_TYPE_DGRAM:
595                 type = SOCK_DGRAM;
596                 break;
597         default:
598                 return NT_STATUS_INVALID_PARAMETER;
599         }
600
601         sock->fd = socket(PF_INET6, type, 0);
602         if (sock->fd == -1) {
603                 return map_nt_error_from_unix(errno);
604         }
605
606         sock->backend_name = "ipv6";
607         sock->family = AF_INET6;
608
609         return NT_STATUS_OK;
610 }
611
612 static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
613                                  const struct socket_address *my_address,
614                                  const struct socket_address *srv_address,
615                                  uint32_t flags)
616 {
617         int ret;
618
619         if (my_address && my_address->sockaddr) {
620                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
621                 if (ret == -1) {
622                         return map_nt_error_from_unix(errno);
623                 }
624         } else if (my_address) {
625                 struct in6_addr my_ip;
626                 my_ip = interpret_addr6(my_address->addr);
627
628                 if (memcmp(&my_ip, &in6addr_any, sizeof(my_ip)) || my_address->port != 0) {
629                         struct sockaddr_in6 my_addr;
630                         ZERO_STRUCT(my_addr);
631                         my_addr.sin6_addr       = my_ip;
632                         my_addr.sin6_port       = htons(my_address->port);
633                         my_addr.sin6_family     = PF_INET6;
634                         
635                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
636                         if (ret == -1) {
637                                 return map_nt_error_from_unix(errno);
638                         }
639                 }
640         }
641
642         if (srv_address->sockaddr) {
643                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
644         } else {
645                 struct in6_addr srv_ip;
646                 struct sockaddr_in6 srv_addr;
647                 srv_ip = interpret_addr6(srv_address->addr);
648                 if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
649                         return NT_STATUS_BAD_NETWORK_NAME;
650                 }
651                 
652                 ZERO_STRUCT(srv_addr);
653                 srv_addr.sin6_addr      = srv_ip;
654                 srv_addr.sin6_port      = htons(srv_address->port);
655                 srv_addr.sin6_family    = PF_INET6;
656                 
657                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
658         }
659         if (ret == -1) {
660                 return map_nt_error_from_unix(errno);
661         }
662
663         return ip_connect_complete(sock, flags);
664 }
665
666 static NTSTATUS ipv6_listen(struct socket_context *sock,
667                                 const struct socket_address *my_address,
668                                 int queue_size, uint32_t flags)
669 {
670         struct sockaddr_in6 my_addr;
671         struct in6_addr ip_addr;
672         int ret;
673
674         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
675
676         if (my_address->sockaddr) {
677                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
678         } else {
679                 ip_addr = interpret_addr6(my_address->addr);
680                 
681                 ZERO_STRUCT(my_addr);
682                 my_addr.sin6_addr       = ip_addr;
683                 my_addr.sin6_port       = htons(my_address->port);
684                 my_addr.sin6_family     = PF_INET6;
685                 
686                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
687         }
688
689         if (ret == -1) {
690                 return map_nt_error_from_unix(errno);
691         }
692
693         if (sock->type == SOCKET_TYPE_STREAM) {
694                 ret = listen(sock->fd, queue_size);
695                 if (ret == -1) {
696                         return map_nt_error_from_unix(errno);
697                 }
698         }
699
700         if (!(flags & SOCKET_FLAG_BLOCK)) {
701                 ret = set_blocking(sock->fd, false);
702                 if (ret == -1) {
703                         return map_nt_error_from_unix(errno);
704                 }
705         }
706
707         sock->state= SOCKET_STATE_SERVER_LISTEN;
708
709         return NT_STATUS_OK;
710 }
711
712 static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
713 {
714         struct sockaddr_in cli_addr;
715         socklen_t cli_addr_len = sizeof(cli_addr);
716         int new_fd;
717         
718         if (sock->type != SOCKET_TYPE_STREAM) {
719                 return NT_STATUS_INVALID_PARAMETER;
720         }
721
722         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
723         if (new_fd == -1) {
724                 return map_nt_error_from_unix(errno);
725         }
726
727         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
728                 int ret = set_blocking(new_fd, false);
729                 if (ret == -1) {
730                         close(new_fd);
731                         return map_nt_error_from_unix(errno);
732                 }
733         }
734
735         /* TODO: we could add a 'accept_check' hook here
736          *       which get the black/white lists via socket_set_accept_filter()
737          *       or something like that
738          *       --metze
739          */
740
741         (*new_sock) = talloc(NULL, struct socket_context);
742         if (!(*new_sock)) {
743                 close(new_fd);
744                 return NT_STATUS_NO_MEMORY;
745         }
746
747         /* copy the socket_context */
748         (*new_sock)->type               = sock->type;
749         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
750         (*new_sock)->flags              = sock->flags;
751
752         (*new_sock)->fd                 = new_fd;
753
754         (*new_sock)->private_data       = NULL;
755         (*new_sock)->ops                = sock->ops;
756         (*new_sock)->backend_name       = sock->backend_name;
757
758         return NT_STATUS_OK;
759 }
760
761 static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, 
762                               size_t wantlen, size_t *nread, 
763                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
764 {
765         ssize_t gotlen;
766         struct sockaddr_in6 *from_addr;
767         socklen_t from_len = sizeof(*from_addr);
768         struct socket_address *src;
769         char addrstring[INET6_ADDRSTRLEN];
770         
771         src = talloc(addr_ctx, struct socket_address);
772         if (!src) {
773                 return NT_STATUS_NO_MEMORY;
774         }
775         
776         src->family = sock->backend_name;
777
778         from_addr = talloc(src, struct sockaddr_in6);
779         if (!from_addr) {
780                 talloc_free(src);
781                 return NT_STATUS_NO_MEMORY;
782         }
783
784         src->sockaddr = (struct sockaddr *)from_addr;
785
786         *nread = 0;
787
788         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
789                           src->sockaddr, &from_len);
790         if (gotlen == 0) {
791                 talloc_free(src);
792                 return NT_STATUS_END_OF_FILE;
793         } else if (gotlen == -1) {
794                 talloc_free(src);
795                 return map_nt_error_from_unix(errno);
796         }
797
798         src->sockaddrlen = from_len;
799
800         if (inet_ntop(AF_INET6, &from_addr->sin6_addr, addrstring, sizeof(addrstring)) == NULL) {
801                 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno)));
802                 talloc_free(src);
803                 return NT_STATUS_INTERNAL_ERROR;
804         }
805
806         src->addr = talloc_strdup(src, addrstring);
807         if (src->addr == NULL) {
808                 talloc_free(src);
809                 return NT_STATUS_NO_MEMORY;
810         }
811         src->port = ntohs(from_addr->sin6_port);
812
813         *nread  = gotlen;
814         *_src   = src;
815         return NT_STATUS_OK;
816 }
817
818 static NTSTATUS ipv6_sendto(struct socket_context *sock, 
819                             const DATA_BLOB *blob, size_t *sendlen, 
820                             const struct socket_address *dest_addr)
821 {
822         ssize_t len;
823
824         if (dest_addr->sockaddr) {
825                 len = sendto(sock->fd, blob->data, blob->length, 0, 
826                              dest_addr->sockaddr, dest_addr->sockaddrlen);
827         } else {
828                 struct sockaddr_in6 srv_addr;
829                 struct in6_addr addr;
830                 
831                 ZERO_STRUCT(srv_addr);
832                 addr                     = interpret_addr6(dest_addr->addr);
833                 if (addr.s6_addr == 0) {
834                         return NT_STATUS_HOST_UNREACHABLE;
835                 }
836                 srv_addr.sin6_addr = addr;
837                 srv_addr.sin6_port        = htons(dest_addr->port);
838                 srv_addr.sin6_family      = PF_INET6;
839                 
840                 *sendlen = 0;
841                 
842                 len = sendto(sock->fd, blob->data, blob->length, 0, 
843                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
844         }
845         if (len == -1) {
846                 return map_nt_error_from_unix(errno);
847         }       
848
849         *sendlen = len;
850
851         return NT_STATUS_OK;
852 }
853
854 static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
855 {
856         set_socket_options(sock->fd, option);
857         return NT_STATUS_OK;
858 }
859
860 static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
861 {
862         struct sockaddr_in6 peer_addr;
863         socklen_t len = sizeof(peer_addr);
864         struct hostent *he;
865         int ret;
866
867         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
868         if (ret == -1) {
869                 return NULL;
870         }
871
872         he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
873         if (he == NULL) {
874                 return NULL;
875         }
876
877         return talloc_strdup(mem_ctx, he->h_name);
878 }
879
880 static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
881 {
882         struct sockaddr_in6 *peer_addr;
883         socklen_t len = sizeof(*peer_addr);
884         struct socket_address *peer;
885         int ret;
886         char addr[128];
887         const char *addr_ret;
888         
889         peer = talloc(mem_ctx, struct socket_address);
890         if (!peer) {
891                 return NULL;
892         }
893         
894         peer->family = sock->backend_name;
895         peer_addr = talloc(peer, struct sockaddr_in6);
896         if (!peer_addr) {
897                 talloc_free(peer);
898                 return NULL;
899         }
900
901         peer->sockaddr = (struct sockaddr *)peer_addr;
902
903         ret = getpeername(sock->fd, peer->sockaddr, &len);
904         if (ret == -1) {
905                 talloc_free(peer);
906                 return NULL;
907         }
908
909         peer->sockaddrlen = len;
910
911         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
912         if (addr_ret == NULL) {
913                 talloc_free(peer);
914                 return NULL;
915         }
916
917         peer->addr = talloc_strdup(peer, addr_ret);
918         if (peer->addr == NULL) {
919                 talloc_free(peer);
920                 return NULL;
921         }
922
923         peer->port = ntohs(peer_addr->sin6_port);
924
925         return peer;
926 }
927
928 static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
929 {
930         struct sockaddr_in6 *local_addr;
931         socklen_t len = sizeof(*local_addr);
932         struct socket_address *local;
933         int ret;
934         char addrstring[INET6_ADDRSTRLEN];
935         
936         local = talloc(mem_ctx, struct socket_address);
937         if (!local) {
938                 return NULL;
939         }
940         
941         local->family = sock->backend_name;
942         local_addr = talloc(local, struct sockaddr_in6);
943         if (!local_addr) {
944                 talloc_free(local);
945                 return NULL;
946         }
947
948         local->sockaddr = (struct sockaddr *)local_addr;
949
950         ret = getsockname(sock->fd, local->sockaddr, &len);
951         if (ret == -1) {
952                 talloc_free(local);
953                 return NULL;
954         }
955
956         local->sockaddrlen = len;
957
958         if (inet_ntop(AF_INET6, &local_addr->sin6_addr, addrstring, 
959                        sizeof(addrstring)) == NULL) {
960                 DEBUG(0, ("Unable to convert address to string: %s\n", 
961                           strerror(errno)));
962                 talloc_free(local);
963                 return NULL;
964         }
965         
966         local->addr = talloc_strdup(mem_ctx, addrstring);
967         if (!local->addr) {
968                 talloc_free(local);
969                 return NULL;
970         }
971         local->port = ntohs(local_addr->sin6_port);
972
973         return local;
974 }
975
976 static const struct socket_ops ipv6_tcp_ops = {
977         .name                   = "ipv6",
978         .fn_init                = ipv6_init,
979         .fn_connect             = ipv6_tcp_connect,
980         .fn_connect_complete    = ip_connect_complete,
981         .fn_listen              = ipv6_listen,
982         .fn_accept              = ipv6_tcp_accept,
983         .fn_recv                = ip_recv,
984         .fn_recvfrom            = ipv6_recvfrom,
985         .fn_send                = ip_send,
986         .fn_sendto              = ipv6_sendto,
987         .fn_pending             = ip_pending,
988         .fn_close               = ip_close,
989
990         .fn_set_option          = ipv6_set_option,
991
992         .fn_get_peer_name       = ipv6_tcp_get_peer_name,
993         .fn_get_peer_addr       = ipv6_tcp_get_peer_addr,
994         .fn_get_my_addr         = ipv6_tcp_get_my_addr,
995
996         .fn_get_fd              = ip_get_fd
997 };
998
999 _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
1000 {
1001         return &ipv6_tcp_ops;
1002 }
1003
1004 #endif