1 /*
2 Unix SMB/CIFS implementation.
3 Socket functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Tim Potter 2000-2001
6 Copyright (C) Stefan Metzmacher 2004
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/socket/socket.h"
24 #include "system/filesys.h"
25 #include "system/network.h"
26 #include "param/param.h"
27 #include "../lib/tsocket/tsocket.h"
28 #include "lib/util/util_net.h"
29
30 /*
31 auto-close sockets on free
32 */
socket_destructor(struct socket_context * sock)33 static int socket_destructor(struct socket_context *sock)
34 {
35 if (sock->ops->fn_close &&
36 !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
37 sock->ops->fn_close(sock);
38 }
39 return 0;
40 }
41
socket_tevent_fd_close_fn(struct tevent_context * ev,struct tevent_fd * fde,int fd,void * private_data)42 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
43 struct tevent_fd *fde,
44 int fd,
45 void *private_data)
46 {
47 /* this might be the socket_wrapper swrap_close() */
48 close(fd);
49 }
50
socket_create_with_ops(TALLOC_CTX * mem_ctx,const struct socket_ops * ops,struct socket_context ** new_sock,enum socket_type type,uint32_t flags)51 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
52 struct socket_context **new_sock,
53 enum socket_type type, uint32_t flags)
54 {
55 NTSTATUS status;
56
57 (*new_sock) = talloc(mem_ctx, struct socket_context);
58 if (!(*new_sock)) {
59 return NT_STATUS_NO_MEMORY;
60 }
61
62 (*new_sock)->type = type;
63 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
64 (*new_sock)->flags = flags;
65
66 (*new_sock)->fd = -1;
67
68 (*new_sock)->private_data = NULL;
69 (*new_sock)->ops = ops;
70 (*new_sock)->backend_name = NULL;
71
72 status = (*new_sock)->ops->fn_init((*new_sock));
73 if (!NT_STATUS_IS_OK(status)) {
74 talloc_free(*new_sock);
75 return status;
76 }
77
78 /* by enabling "testnonblock" mode, all socket receive and
79 send calls on non-blocking sockets will randomly recv/send
80 less data than requested */
81
82 if (!(flags & SOCKET_FLAG_BLOCK) &&
83 type == SOCKET_TYPE_STREAM &&
84 getenv("SOCKET_TESTNONBLOCK") != NULL) {
85 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
86 }
87
88 /* we don't do a connect() on dgram sockets, so need to set
89 non-blocking at socket create time */
90 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
91 set_blocking(socket_get_fd(*new_sock), false);
92 }
93
94 talloc_set_destructor(*new_sock, socket_destructor);
95
96 return NT_STATUS_OK;
97 }
98
socket_create(TALLOC_CTX * mem_ctx,const char * name,enum socket_type type,struct socket_context ** new_sock,uint32_t flags)99 _PUBLIC_ NTSTATUS socket_create(TALLOC_CTX *mem_ctx,
100 const char *name, enum socket_type type,
101 struct socket_context **new_sock, uint32_t flags)
102 {
103 const struct socket_ops *ops;
104
105 ops = socket_getops_byname(name, type);
106 if (!ops) {
107 return NT_STATUS_INVALID_PARAMETER;
108 }
109
110 return socket_create_with_ops(mem_ctx, ops, new_sock, type, flags);
111 }
112
socket_connect(struct socket_context * sock,const struct socket_address * my_address,const struct socket_address * server_address,uint32_t flags)113 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
114 const struct socket_address *my_address,
115 const struct socket_address *server_address,
116 uint32_t flags)
117 {
118 if (sock == NULL) {
119 return NT_STATUS_CONNECTION_DISCONNECTED;
120 }
121 if (sock->state != SOCKET_STATE_UNDEFINED) {
122 return NT_STATUS_INVALID_PARAMETER;
123 }
124
125 if (!sock->ops->fn_connect) {
126 return NT_STATUS_NOT_IMPLEMENTED;
127 }
128
129 return sock->ops->fn_connect(sock, my_address, server_address, flags);
130 }
131
socket_connect_complete(struct socket_context * sock,uint32_t flags)132 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
133 {
134 if (!sock->ops->fn_connect_complete) {
135 return NT_STATUS_NOT_IMPLEMENTED;
136 }
137 return sock->ops->fn_connect_complete(sock, flags);
138 }
139
socket_listen(struct socket_context * sock,const struct socket_address * my_address,int queue_size,uint32_t flags)140 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
141 const struct socket_address *my_address,
142 int queue_size, uint32_t flags)
143 {
144 if (sock == NULL) {
145 return NT_STATUS_CONNECTION_DISCONNECTED;
146 }
147 if (sock->state != SOCKET_STATE_UNDEFINED) {
148 return NT_STATUS_INVALID_PARAMETER;
149 }
150
151 if (!sock->ops->fn_listen) {
152 return NT_STATUS_NOT_IMPLEMENTED;
153 }
154
155 return sock->ops->fn_listen(sock, my_address, queue_size, flags);
156 }
157
socket_accept(struct socket_context * sock,struct socket_context ** new_sock)158 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
159 {
160 NTSTATUS status;
161
162 if (sock == NULL) {
163 return NT_STATUS_CONNECTION_DISCONNECTED;
164 }
165 if (sock->type != SOCKET_TYPE_STREAM) {
166 return NT_STATUS_INVALID_PARAMETER;
167 }
168
169 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
170 return NT_STATUS_INVALID_PARAMETER;
171 }
172
173 if (!sock->ops->fn_accept) {
174 return NT_STATUS_NOT_IMPLEMENTED;
175 }
176
177 status = sock->ops->fn_accept(sock, new_sock);
178
179 if (NT_STATUS_IS_OK(status)) {
180 talloc_set_destructor(*new_sock, socket_destructor);
181 (*new_sock)->flags = 0;
182 }
183
184 return status;
185 }
186
socket_recv(struct socket_context * sock,void * buf,size_t wantlen,size_t * nread)187 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
188 size_t wantlen, size_t *nread)
189 {
190 if (sock == NULL) {
191 return NT_STATUS_CONNECTION_DISCONNECTED;
192 }
193 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
194 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
195 sock->type != SOCKET_TYPE_DGRAM) {
196 return NT_STATUS_INVALID_PARAMETER;
197 }
198
199 if (!sock->ops->fn_recv) {
200 return NT_STATUS_NOT_IMPLEMENTED;
201 }
202
203 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
204 && wantlen > 1) {
205
206 if (random() % 10 == 0) {
207 *nread = 0;
208 return STATUS_MORE_ENTRIES;
209 }
210 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
211 }
212 return sock->ops->fn_recv(sock, buf, wantlen, nread);
213 }
214
socket_recvfrom(struct socket_context * sock,void * buf,size_t wantlen,size_t * nread,TALLOC_CTX * mem_ctx,struct socket_address ** src_addr)215 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
216 size_t wantlen, size_t *nread,
217 TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
218 {
219 if (sock == NULL) {
220 return NT_STATUS_CONNECTION_DISCONNECTED;
221 }
222 if (sock->type != SOCKET_TYPE_DGRAM) {
223 return NT_STATUS_INVALID_PARAMETER;
224 }
225
226 if (!sock->ops->fn_recvfrom) {
227 return NT_STATUS_NOT_IMPLEMENTED;
228 }
229
230 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
231 mem_ctx, src_addr);
232 }
233
socket_send(struct socket_context * sock,const DATA_BLOB * blob,size_t * sendlen)234 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
235 const DATA_BLOB *blob, size_t *sendlen)
236 {
237 if (sock == NULL) {
238 return NT_STATUS_CONNECTION_DISCONNECTED;
239 }
240 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
241 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
242 return NT_STATUS_INVALID_PARAMETER;
243 }
244
245 if (!sock->ops->fn_send) {
246 return NT_STATUS_NOT_IMPLEMENTED;
247 }
248
249 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
250 && blob->length > 1) {
251 DATA_BLOB blob2 = *blob;
252 if (random() % 10 == 0) {
253 *sendlen = 0;
254 return STATUS_MORE_ENTRIES;
255 }
256 /* The random size sends are incompatible with TLS and SASL
257 * sockets, which require re-sends to be consistant */
258 if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
259 blob2.length = 1+(random() % blob2.length);
260 } else {
261 /* This is particularly stressful on buggy
262 * LDAP clients, that don't expect on LDAP
263 * packet in many SASL packets */
264 blob2.length = 1 + blob2.length/2;
265 }
266 return sock->ops->fn_send(sock, &blob2, sendlen);
267 }
268 return sock->ops->fn_send(sock, blob, sendlen);
269 }
270
271
socket_sendto(struct socket_context * sock,const DATA_BLOB * blob,size_t * sendlen,const struct socket_address * dest_addr)272 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
273 const DATA_BLOB *blob, size_t *sendlen,
274 const struct socket_address *dest_addr)
275 {
276 if (sock == NULL) {
277 return NT_STATUS_CONNECTION_DISCONNECTED;
278 }
279 if (sock->type != SOCKET_TYPE_DGRAM) {
280 return NT_STATUS_INVALID_PARAMETER;
281 }
282
283 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
284 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
285 return NT_STATUS_INVALID_PARAMETER;
286 }
287
288 if (!sock->ops->fn_sendto) {
289 return NT_STATUS_NOT_IMPLEMENTED;
290 }
291
292 return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
293 }
294
295
296 /*
297 ask for the number of bytes in a pending incoming packet
298 */
socket_pending(struct socket_context * sock,size_t * npending)299 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
300 {
301 if (sock == NULL) {
302 return NT_STATUS_CONNECTION_DISCONNECTED;
303 }
304 if (!sock->ops->fn_pending) {
305 return NT_STATUS_NOT_IMPLEMENTED;
306 }
307 return sock->ops->fn_pending(sock, npending);
308 }
309
310
socket_set_option(struct socket_context * sock,const char * option,const char * val)311 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
312 {
313 if (sock == NULL) {
314 return NT_STATUS_CONNECTION_DISCONNECTED;
315 }
316 if (!sock->ops->fn_set_option) {
317 return NT_STATUS_NOT_IMPLEMENTED;
318 }
319
320 return sock->ops->fn_set_option(sock, option, val);
321 }
322
socket_get_peer_name(struct socket_context * sock,TALLOC_CTX * mem_ctx)323 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
324 {
325 if (!sock->ops->fn_get_peer_name) {
326 return NULL;
327 }
328
329 return sock->ops->fn_get_peer_name(sock, mem_ctx);
330 }
331
socket_get_peer_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)332 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
333 {
334 if (!sock->ops->fn_get_peer_addr) {
335 return NULL;
336 }
337
338 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
339 }
340
socket_get_my_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)341 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
342 {
343 if (!sock->ops->fn_get_my_addr) {
344 return NULL;
345 }
346
347 return sock->ops->fn_get_my_addr(sock, mem_ctx);
348 }
349
socket_address_to_tsocket_address(TALLOC_CTX * mem_ctx,const struct socket_address * a)350 _PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
351 const struct socket_address *a)
352 {
353 struct tsocket_address *r;
354 int ret;
355
356 if (!a) {
357 return NULL;
358 }
359 if (a->sockaddr) {
360 ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
361 a->sockaddr,
362 a->sockaddrlen,
363 &r);
364 } else {
365 ret = tsocket_address_inet_from_strings(mem_ctx,
366 a->family,
367 a->addr,
368 a->port,
369 &r);
370 }
371
372 if (ret != 0) {
373 return NULL;
374 }
375
376 return r;
377 }
378
socket_address_set_port(struct socket_address * a,uint16_t port)379 _PUBLIC_ void socket_address_set_port(struct socket_address *a,
380 uint16_t port)
381 {
382 if (a->sockaddr) {
383 set_sockaddr_port(a->sockaddr, port);
384 } else {
385 a->port = port;
386 }
387
388 }
389
tsocket_address_to_socket_address(TALLOC_CTX * mem_ctx,const struct tsocket_address * a)390 _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
391 const struct tsocket_address *a)
392 {
393 ssize_t ret;
394 struct sockaddr_storage ss;
395 size_t sslen = sizeof(ss);
396
397 ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
398 if (ret < 0) {
399 return NULL;
400 }
401
402 return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
403 }
404
socket_get_remote_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)405 _PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
406 {
407 struct socket_address *a;
408 struct tsocket_address *r;
409
410 a = socket_get_peer_addr(sock, mem_ctx);
411 if (a == NULL) {
412 return NULL;
413 }
414
415 r = socket_address_to_tsocket_address(mem_ctx, a);
416 talloc_free(a);
417 return r;
418 }
419
socket_get_local_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)420 _PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
421 {
422 struct socket_address *a;
423 struct tsocket_address *r;
424
425 a = socket_get_my_addr(sock, mem_ctx);
426 if (a == NULL) {
427 return NULL;
428 }
429
430 r = socket_address_to_tsocket_address(mem_ctx, a);
431 talloc_free(a);
432 return r;
433 }
434
socket_get_fd(struct socket_context * sock)435 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
436 {
437 if (!sock->ops->fn_get_fd) {
438 return -1;
439 }
440
441 return sock->ops->fn_get_fd(sock);
442 }
443
444 /*
445 call dup() on a socket, and close the old fd. This is used to change
446 the fd to the lowest available number, to make select() more
447 efficient (select speed depends on the maxiumum fd number passed to
448 it)
449 */
socket_dup(struct socket_context * sock)450 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
451 {
452 int fd;
453 if (sock->fd == -1) {
454 return NT_STATUS_INVALID_HANDLE;
455 }
456 fd = dup(sock->fd);
457 if (fd == -1) {
458 return map_nt_error_from_unix_common(errno);
459 }
460 close(sock->fd);
461 sock->fd = fd;
462 return NT_STATUS_OK;
463
464 }
465
466 /* Create a new socket_address. The type must match the socket type.
467 * The host parameter may be an IP or a hostname
468 */
469
socket_address_from_strings(TALLOC_CTX * mem_ctx,const char * family,const char * host,int port)470 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
471 const char *family,
472 const char *host,
473 int port)
474 {
475 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
476 if (!addr) {
477 return NULL;
478 }
479
480 if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) {
481 /* leaving as "ip" would force IPv4 */
482 family = "ipv6";
483 }
484
485 addr->family = family;
486 addr->addr = talloc_strdup(addr, host);
487 if (!addr->addr) {
488 talloc_free(addr);
489 return NULL;
490 }
491 addr->port = port;
492 addr->sockaddr = NULL;
493 addr->sockaddrlen = 0;
494
495 return addr;
496 }
497
498 /* Create a new socket_address. Copy the struct sockaddr into the new
499 * structure. Used for hooks in the kerberos libraries, where they
500 * supply only a struct sockaddr */
501
socket_address_from_sockaddr(TALLOC_CTX * mem_ctx,struct sockaddr * sockaddr,size_t sockaddrlen)502 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
503 struct sockaddr *sockaddr,
504 size_t sockaddrlen)
505 {
506 struct socket_address *addr = talloc(mem_ctx, struct socket_address);
507 if (!addr) {
508 return NULL;
509 }
510 switch (sockaddr->sa_family) {
511 case AF_INET:
512 addr->family = "ipv4";
513 break;
514 #ifdef HAVE_IPV6
515 case AF_INET6:
516 addr->family = "ipv6";
517 break;
518 #endif
519 case AF_UNIX:
520 addr->family = "unix";
521 break;
522 }
523 addr->addr = NULL;
524 addr->port = 0;
525 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
526 if (!addr->sockaddr) {
527 talloc_free(addr);
528 return NULL;
529 }
530 addr->sockaddrlen = sockaddrlen;
531 return addr;
532 }
533
534
535 /*
536 Create a new socket_address from sockaddr_storage
537 */
socket_address_from_sockaddr_storage(TALLOC_CTX * mem_ctx,const struct sockaddr_storage * sockaddr,uint16_t port)538 _PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx,
539 const struct sockaddr_storage *sockaddr,
540 uint16_t port)
541 {
542 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
543 char addr_str[INET6_ADDRSTRLEN+1];
544 const char *str;
545
546 if (!addr) {
547 return NULL;
548 }
549 addr->port = port;
550 switch (sockaddr->ss_family) {
551 case AF_INET:
552 addr->family = "ipv4";
553 break;
554 #ifdef HAVE_IPV6
555 case AF_INET6:
556 addr->family = "ipv6";
557 break;
558 #endif
559 default:
560 talloc_free(addr);
561 return NULL;
562 }
563
564 str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr);
565 if (str == NULL) {
566 talloc_free(addr);
567 return NULL;
568 }
569 addr->addr = talloc_strdup(addr, str);
570 if (addr->addr == NULL) {
571 talloc_free(addr);
572 return NULL;
573 }
574
575 return addr;
576 }
577
578 /* Copy a socket_address structure */
socket_address_copy(TALLOC_CTX * mem_ctx,const struct socket_address * oaddr)579 struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
580 const struct socket_address *oaddr)
581 {
582 struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
583 if (!addr) {
584 return NULL;
585 }
586 addr->family = oaddr->family;
587 if (oaddr->addr) {
588 addr->addr = talloc_strdup(addr, oaddr->addr);
589 if (!addr->addr) {
590 goto nomem;
591 }
592 }
593 addr->port = oaddr->port;
594 if (oaddr->sockaddr) {
595 addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
596 oaddr->sockaddr,
597 oaddr->sockaddrlen);
598 if (!addr->sockaddr) {
599 goto nomem;
600 }
601 addr->sockaddrlen = oaddr->sockaddrlen;
602 }
603
604 return addr;
605
606 nomem:
607 talloc_free(addr);
608 return NULL;
609 }
610
socket_getops_byname(const char * family,enum socket_type type)611 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
612 {
613 extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
614 extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
615 extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
616
617 if (strcmp("ip", family) == 0 ||
618 strcmp("ipv4", family) == 0) {
619 return socket_ipv4_ops(type);
620 }
621
622 #ifdef HAVE_IPV6
623 if (strcmp("ipv6", family) == 0) {
624 return socket_ipv6_ops(type);
625 }
626 #endif
627
628 if (strcmp("unix", family) == 0) {
629 return socket_unixdom_ops(type);
630 }
631
632 return NULL;
633 }
634
635 /*
636 set some flags on a socket
637 */
socket_set_flags(struct socket_context * sock,unsigned flags)638 void socket_set_flags(struct socket_context *sock, unsigned flags)
639 {
640 sock->flags |= flags;
641 }
642