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