Coverage Report

Created: 2026-06-07 07:07

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