lib: Properly return errno from open_socket_in()
authorVolker Lendecke <vl@samba.org>
Fri, 12 Feb 2021 20:27:19 +0000 (21:27 +0100)
committerVolker Lendecke <vl@samba.org>
Fri, 19 Mar 2021 07:09:37 +0000 (07:09 +0000)
Before this patch, open_socket_in() relied on quite a bit of code to
not touch errno after for example socket() returned -1. Change this to
explicitly save errno in "ret", such that a later DEBUG() with all its
formatting code can mess it up.

While there, remove the debuglevel parameter. I don't think this
actually useful.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/include/proto.h
source3/lib/util_sock.c
source3/nmbd/nmbd.c
source3/nmbd/nmbd_subnetdb.c
source3/rpc_server/rpc_sock_helper.c
source3/smbd/server.c
source3/utils/nmblookup.c
source3/utils/smbfilter.c

index 1d5ebecb03c9d81c4ffafef5c15afdec6f4e9d98..dd2625292125809f8c4be5caaba7fe3d86dbacfb 100644 (file)
@@ -515,11 +515,11 @@ NTSTATUS receive_smb_raw(int fd,
                        unsigned int timeout,
                        size_t maxlen,
                        size_t *p_len);
-int open_socket_in(int type,
-               uint16_t port,
-               int dlevel,
-               const struct sockaddr_storage *psock,
-               bool rebind);
+int open_socket_in(
+       int type,
+       const struct sockaddr_storage *paddr,
+       uint16_t port,
+       bool rebind);
 NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port,
                         int timeout, int *pfd);
 struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
index 97415011097788827e15ce047e1e2217f281c2c1..2dbb572a974d7c1bf9238c8ac661e8143a9a52cd 100644 (file)
@@ -234,67 +234,59 @@ NTSTATUS receive_smb_raw(int fd, char *buffer, size_t buflen, unsigned int timeo
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- Open a socket of the specified type, port, and address for incoming data.
-****************************************************************************/
-
-int open_socket_in(int type,
-               uint16_t port,
-               int dlevel,
-               const struct sockaddr_storage *psock,
-               bool rebind)
+/*
+ * Open a socket of the specified type, port, and address for incoming data.
+ *
+ * Return sock or -errno
+ */
+
+int open_socket_in(
+       int type,
+       const struct sockaddr_storage *paddr,
+       uint16_t port,
+       bool rebind)
 {
-       struct sockaddr_storage sock;
-       int res;
-       socklen_t slen = sizeof(struct sockaddr_in);
-
-       sock = *psock;
+       struct samba_sockaddr addr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+               .u.ss = *paddr,
+       };
+       int ret, sock = -1;
+       int val = rebind ? 1 : 0;
+       bool ok;
 
-#if defined(HAVE_IPV6)
-       if (sock.ss_family == AF_INET6) {
-               ((struct sockaddr_in6 *)&sock)->sin6_port = htons(port);
-               slen = sizeof(struct sockaddr_in6);
+       ok = samba_sockaddr_set_port(&addr, port);
+       if (!ok) {
+               ret = -EINVAL;
+               DBG_DEBUG("samba_sockaddr_set_port failed\n");
+               goto fail;
        }
-#endif
-       if (sock.ss_family == AF_INET) {
-               ((struct sockaddr_in *)&sock)->sin_port = htons(port);
+
+       sock = socket(addr.u.ss.ss_family, type, 0 );
+       if (sock == -1) {
+               ret = -errno;
+               DBG_DEBUG("socket() failed: %s\n", strerror(errno));
+               goto fail;
        }
 
-       res = socket(sock.ss_family, type, 0 );
-       if( res == -1 ) {
-               if( DEBUGLVL(0) ) {
-                       dbgtext( "open_socket_in(): socket() call failed: " );
-                       dbgtext( "%s\n", strerror( errno ) );
-               }
-               return -1;
+       ret = setsockopt(
+               sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+       if (ret == -1) {
+               ret = -errno;
+               DBG_DEBUG("setsockopt(SO_REUSEADDR) failed: %s\n",
+                         strerror(errno));
+               goto fail;
        }
 
-       /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
-       {
-               int val = rebind ? 1 : 0;
-               if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,
-                                       (char *)&val,sizeof(val)) == -1 ) {
-                       if( DEBUGLVL( dlevel ) ) {
-                               dbgtext( "open_socket_in(): setsockopt: " );
-                               dbgtext( "SO_REUSEADDR = %s ",
-                                               val?"true":"false" );
-                               dbgtext( "on port %d failed ", port );
-                               dbgtext( "with error = %s\n", strerror(errno) );
-                       }
-               }
 #ifdef SO_REUSEPORT
-               if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,
-                                       (char *)&val,sizeof(val)) == -1 ) {
-                       if( DEBUGLVL( dlevel ) ) {
-                               dbgtext( "open_socket_in(): setsockopt: ");
-                               dbgtext( "SO_REUSEPORT = %s ",
-                                               val?"true":"false");
-                               dbgtext( "on port %d failed ", port);
-                               dbgtext( "with error = %s\n", strerror(errno));
-                       }
-               }
-#endif /* SO_REUSEPORT */
+       ret = setsockopt(
+               sock, SOL_SOCKET, SO_REUSEPORT, (char *)&val, sizeof(val));
+       if (ret == -1) {
+               ret = -errno;
+               DBG_DEBUG("setsockopt(SO_REUSEPORT) failed: %s\n",
+                         strerror(errno));
+               goto fail;
        }
+#endif /* SO_REUSEPORT */
 
 #ifdef HAVE_IPV6
        /*
@@ -305,41 +297,50 @@ int open_socket_in(int type,
         * and makes sure %I never resolves to a '::ffff:192.168.0.1'
         * string.
         */
-       if (sock.ss_family == AF_INET6) {
-               int val = 1;
-               int ret;
+       if (addr.u.ss.ss_family == AF_INET6) {
+
+               val = 1;
 
-               ret = setsockopt(res, IPPROTO_IPV6, IPV6_V6ONLY,
-                                (const void *)&val, sizeof(val));
+               ret = setsockopt(
+                       sock,
+                       IPPROTO_IPV6,
+                       IPV6_V6ONLY,
+                       (const void *)&val,
+                       sizeof(val));
                if (ret == -1) {
-                       if(DEBUGLVL(0)) {
-                               dbgtext("open_socket_in(): IPV6_ONLY failed: ");
-                               dbgtext("%s\n", strerror(errno));
-                       }
-                       close(res);
-                       return -1;
+                       ret = -errno;
+                       DBG_DEBUG("setsockopt(IPV6_V6ONLY) failed: %s\n",
+                                 strerror(errno));
+                       goto fail;
                }
        }
 #endif
 
        /* now we've got a socket - we need to bind it */
-       if (bind(res, (struct sockaddr *)&sock, slen) == -1 ) {
-               if( DEBUGLVL(dlevel) && (port == NMB_PORT ||
-                                        port == NBT_SMB_PORT ||
-                                        port == TCP_SMB_PORT) ) {
-                       char addr[INET6_ADDRSTRLEN];
-                       print_sockaddr(addr, sizeof(addr),
-                                       &sock);
-                       dbgtext( "bind failed on port %d ", port);
-                       dbgtext( "socket_addr = %s.\n", addr);
-                       dbgtext( "Error = %s\n", strerror(errno));
-               }
-               close(res);
-               return -1;
+       ret = bind(sock, &addr.u.sa, addr.sa_socklen);
+       if (ret == -1) {
+               char addrstr[INET6_ADDRSTRLEN];
+
+               ret = -errno;
+
+               print_sockaddr(addrstr, sizeof(addrstr), &addr.u.ss);
+               DBG_DEBUG("bind for %s port %"PRIu16" failed: %s\n",
+                         addrstr,
+                         port,
+                         strerror(-ret));
+               goto fail;
        }
 
-       DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
-       return( res );
+       DBG_DEBUG("bind succeeded on port %"PRIu16"\n", port);
+
+       return sock;
+
+fail:
+       if (sock != -1) {
+               close(sock);
+               sock = -1;
+       }
+       return ret;
  }
 
 struct open_socket_out_state {
index 1f7e81a5473565eac1335f1d46dbc55f2453e604..dce746a833971da73e1dbe40a4d68cb610bfc2a9 100644 (file)
@@ -733,22 +733,18 @@ static bool open_sockets(bool isdaemon, int port)
        }
 
        if (isdaemon) {
-               ClientNMB = open_socket_in(SOCK_DGRAM, port,
-                                          0, &ss,
-                                          true);
+               ClientNMB = open_socket_in(SOCK_DGRAM, &ss, port, true);
        } else {
                ClientNMB = 0;
        }
 
-       if (ClientNMB == -1) {
+       if (ClientNMB < 0) {
                return false;
        }
 
-       ClientDGRAM = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
-                                          3, &ss,
-                                          true);
+       ClientDGRAM = open_socket_in(SOCK_DGRAM, &ss, DGRAM_PORT, true);
 
-       if (ClientDGRAM == -1) {
+       if (ClientDGRAM < 0) {
                if (ClientNMB != 0) {
                        close(ClientNMB);
                }
index 5c9e4c7eb26524541b84fba2193112a1e2fc7589..38c6db69b3db97e7bbdf311ed9df3c5f5d88ccf3 100644 (file)
@@ -107,56 +107,55 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type
                 * Fail the subnet creation if this fails.
                 */
 
-               nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
-                                         0, &ss, true);
-               if (nmb_sock == -1) {
-                       DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
-                       DEBUGADD(0,("  Failed to open nmb socket on interface %s ",
-                                   inet_ntoa(myip)));
-                       DEBUGADD(0,("for port %d.  ", global_nmb_port));
-                       DEBUGADD(0,("Error was %s\n", strerror(errno)));
+               nmb_sock = open_socket_in(
+                       SOCK_DGRAM, &ss, global_nmb_port, true);
+               if (nmb_sock < 0) {
+                       DBG_ERR("Failed to open nmb socket on interface %s "
+                               "for port %d: %s\n",
+                               inet_ntoa(myip),
+                               global_nmb_port,
+                               strerror(-nmb_sock));
                        goto failed;
                }
                set_socket_options(nmb_sock,"SO_BROADCAST");
                set_blocking(nmb_sock, false);
 
                if (bind_bcast) {
-                       nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port,
-                                                  0, &ss_bcast, true);
-                       if (nmb_bcast == -1) {
-                               DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
-                               DEBUGADD(0,("  Failed to open nmb bcast socket on interface %s ",
-                                           inet_ntoa(bcast_ip)));
-                               DEBUGADD(0,("for port %d.  ", global_nmb_port));
-                               DEBUGADD(0,("Error was %s\n", strerror(errno)));
+                       nmb_bcast = open_socket_in(
+                               SOCK_DGRAM, &ss_bcast, global_nmb_port, true);
+                       if (nmb_bcast < 0) {
+                               DBG_ERR("Failed to open nmb bcast socket on "
+                                       "interface %s for port %d: %s\n",
+                                       inet_ntoa(myip),
+                                       global_nmb_port,
+                                       strerror(-nmb_bcast));
                                goto failed;
                        }
                        set_socket_options(nmb_bcast, "SO_BROADCAST");
                        set_blocking(nmb_bcast, false);
                }
 
-               dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
-                                           3, &ss, true);
-               if (dgram_sock == -1) {
-                       DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
-                       DEBUGADD(0,("  Failed to open dgram socket on interface %s ",
-                                   inet_ntoa(myip)));
-                       DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
-                       DEBUGADD(0,("Error was %s\n", strerror(errno)));
+               dgram_sock = open_socket_in(SOCK_DGRAM, &ss, DGRAM_PORT, true);
+               if (dgram_sock < 0) {
+                       DBG_ERR("Failed to open dgram socket on "
+                               "interface %s for port %d: %s\n",
+                               inet_ntoa(myip),
+                               DGRAM_PORT,
+                               strerror(-dgram_sock));
                        goto failed;
                }
                set_socket_options(dgram_sock, "SO_BROADCAST");
                set_blocking(dgram_sock, false);
 
                if (bind_bcast) {
-                       dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
-                                                    3, &ss_bcast, true);
-                       if (dgram_bcast == -1) {
-                               DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
-                               DEBUGADD(0,("  Failed to open dgram bcast socket on interface %s ",
-                                           inet_ntoa(bcast_ip)));
-                               DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
-                               DEBUGADD(0,("Error was %s\n", strerror(errno)));
+                       dgram_bcast = open_socket_in(
+                               SOCK_DGRAM, &ss_bcast, DGRAM_PORT, true);
+                       if (dgram_bcast < 0) {
+                               DBG_ERR("Failed to open dgram bcast socket on "
+                                       "interface %s for port %d: %s\n",
+                                       inet_ntoa(myip),
+                                       DGRAM_PORT,
+                                       strerror(-dgram_sock));
                                goto failed;
                        }
                        set_socket_options(dgram_bcast, "SO_BROADCAST");
index 5756a89154418770225aefcfbddb16bd05f0b57e..7308338b71fbf3b18aca7ac54d4ea77ae523c6e9 100644 (file)
@@ -120,26 +120,19 @@ static NTSTATUS dcesrv_create_ncacn_ip_tcp_socket(
                uint16_t i;
 
                for (i = lp_rpc_low_port(); i <= lp_rpc_high_port(); i++) {
-                       fd = open_socket_in(SOCK_STREAM,
-                                           i,
-                                           0,
-                                           ifss,
-                                           false);
+                       fd = open_socket_in(SOCK_STREAM, ifss, i, false);
                        if (fd >= 0) {
                                *port = i;
                                break;
                        }
                }
        } else {
-               fd = open_socket_in(SOCK_STREAM,
-                                   *port,
-                                   0,
-                                   ifss,
-                                   true);
+               fd = open_socket_in(SOCK_STREAM, ifss, *port, true);
        }
-       if (fd == -1) {
+
+       if (fd < 0) {
                DBG_ERR("Failed to create socket on port %u!\n", *port);
-               return NT_STATUS_UNSUCCESSFUL;
+               return map_nt_error_from_unix(-fd);
        }
 
        /* ready to listen */
index 8dd3068bf089954c13d4320a87c96724a91c6476..3ca71f4e71888bd87601aabad02237148b011ff9 100644 (file)
@@ -1073,14 +1073,11 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent,
        }
 
        s->parent = parent;
-       s->fd = open_socket_in(SOCK_STREAM,
-                              port,
-                              parent->sockets == NULL ? 0 : 2,
-                              ifss,
-                              true);
-       if (s->fd == -1) {
-               DEBUG(0,("smbd_open_one_socket: open_socket_in: "
-                       "%s\n", strerror(errno)));
+
+       s->fd = open_socket_in(SOCK_STREAM, ifss, port, true);
+       if (s->fd < 0) {
+               int err = -(s->fd);
+               DBG_ERR("open_socket_in failed: %s\n", strerror(err));
                TALLOC_FREE(s);
                /*
                 * We ignore an error here, as we've done before
index e9e16109e884956ad8a231a9c26aaf6d08520a69..f718e47a98fb40ebc69887edd84638e71726ea41 100644 (file)
@@ -50,12 +50,16 @@ static bool open_sockets(void)
                                        "from string %s", sock_addr));
                return false;
        }
-       ServerFD = open_socket_in( SOCK_DGRAM,
-                               (RootPort ? 137 : 0),
-                               (RootPort ?   0 : 3),
-                               &ss, true );
-
-       if (ServerFD == -1) {
+       ServerFD = open_socket_in(
+               SOCK_DGRAM, &ss, (RootPort ? 137 : 0), true);
+       if (ServerFD < 0) {
+               if (RootPort) {
+                       DBG_ERR("open_socket_in failed: %s\n",
+                               strerror(-ServerFD));
+               } else {
+                       DBG_NOTICE("open_socket_in failed: %s\n",
+                                  strerror(-ServerFD));
+               }
                return false;
        }
 
index 35fb7521384fd1ada862bc879cf10f52c524fe3f..3fbd63975c92c6d60d68fad3d9514558fc6e5732 100644 (file)
@@ -284,10 +284,10 @@ static void start_filter(char *desthost)
        /* start listening on port 445 locally */
 
        zero_sockaddr(&my_ss);
-       s = open_socket_in(SOCK_STREAM, TCP_SMB_PORT, 0, &my_ss, True);
+       s = open_socket_in(SOCK_STREAM, &my_ss, TCP_SMB_PORT, true);
 
-       if (s == -1) {
-               d_printf("bind failed\n");
+       if (s < 0) {
+               d_printf("bind failed: %s\n", strerror(-s));
                exit(1);
        }