smbd: Move reply_special to smb2_reply.c
authorDavid Mulder <dmulder@suse.com>
Thu, 17 Mar 2022 17:04:28 +0000 (11:04 -0600)
committerJeremy Allison <jra@samba.org>
Thu, 7 Apr 2022 17:37:29 +0000 (17:37 +0000)
Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/proto.h
source3/smbd/reply.c
source3/smbd/smb2_reply.c

index f6d10badb292613690462df78ec19b39594bccf4..f791ad5dad9682bbd8cc30cada8b2198fe6d7dd5 100644 (file)
@@ -912,7 +912,6 @@ bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
 
 /* The following definitions come from smbd/reply.c  */
 
-void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size);
 void reply_tcon(struct smb_request *req);
 void reply_tcon_and_X(struct smb_request *req);
 void reply_unknown_new(struct smb_request *req, uint8_t type);
@@ -1036,6 +1035,7 @@ bool check_fsp(connection_struct *conn, struct smb_request *req,
               files_struct *fsp);
 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
                              files_struct *fsp);
+void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size);
 
 /* The following definitions come from smbd/seal.c  */
 
index b304202c36e51c9107064c0c0f1700afed5c5d99..dc06d467cf70eabaa8f7cd0a13dd5eee5198a7ab 100644 (file)
 #include "source3/printing/rap_jobid.h"
 #include "source3/lib/substitute.h"
 
-/****************************************************************************
- Return the port number we've bound to on a socket.
-****************************************************************************/
-
-static int get_socket_port(int fd)
-{
-       struct samba_sockaddr saddr = {
-               .sa_socklen = sizeof(struct sockaddr_storage),
-       };
-
-       if (fd == -1) {
-               return -1;
-       }
-
-       if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
-               int level = (errno == ENOTCONN) ? 2 : 0;
-               DEBUG(level, ("getsockname failed. Error was %s\n",
-                              strerror(errno)));
-               return -1;
-       }
-
-#if defined(HAVE_IPV6)
-       if (saddr.u.sa.sa_family == AF_INET6) {
-               return ntohs(saddr.u.in6.sin6_port);
-       }
-#endif
-       if (saddr.u.sa.sa_family == AF_INET) {
-               return ntohs(saddr.u.in.sin_port);
-       }
-       return -1;
-}
-
-static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
-                                    const char *name, int name_type)
-{
-       char *trim_name;
-       char *trim_name_type;
-       const char *retarget_parm;
-       char *retarget;
-       char *p;
-       int retarget_type = 0x20;
-       int retarget_port = NBT_SMB_PORT;
-       struct sockaddr_storage retarget_addr;
-       struct sockaddr_in *in_addr;
-       bool ret = false;
-       uint8_t outbuf[10];
-
-       if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
-               return false;
-       }
-
-       trim_name = talloc_strdup(talloc_tos(), name);
-       if (trim_name == NULL) {
-               goto fail;
-       }
-       trim_char(trim_name, ' ', ' ');
-
-       trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
-                                        name_type);
-       if (trim_name_type == NULL) {
-               goto fail;
-       }
-
-       retarget_parm = lp_parm_const_string(-1, "netbios retarget",
-                                            trim_name_type, NULL);
-       if (retarget_parm == NULL) {
-               retarget_parm = lp_parm_const_string(-1, "netbios retarget",
-                                                    trim_name, NULL);
-       }
-       if (retarget_parm == NULL) {
-               goto fail;
-       }
-
-       retarget = talloc_strdup(trim_name, retarget_parm);
-       if (retarget == NULL) {
-               goto fail;
-       }
-
-       DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
-
-       p = strchr(retarget, ':');
-       if (p != NULL) {
-               *p++ = '\0';
-               retarget_port = atoi(p);
-       }
-
-       p = strchr_m(retarget, '#');
-       if (p != NULL) {
-               *p++ = '\0';
-               if (sscanf(p, "%x", &retarget_type) != 1) {
-                       goto fail;
-               }
-       }
-
-       ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
-       if (!ret) {
-               DEBUG(10, ("could not resolve %s\n", retarget));
-               goto fail;
-       }
-
-       if (retarget_addr.ss_family != AF_INET) {
-               DEBUG(10, ("Retarget target not an IPv4 addr\n"));
-               goto fail;
-       }
-
-       in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
-
-       _smb_setlen(outbuf, 6);
-       SCVAL(outbuf, 0, 0x84);
-       *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
-       *(uint16_t *)(outbuf+8) = htons(retarget_port);
-
-       if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
-                         NULL)) {
-               exit_server_cleanly("netbios_session_retarget: srv_send_smb "
-                                   "failed.");
-       }
-
-       ret = true;
- fail:
-       TALLOC_FREE(trim_name);
-       return ret;
-}
-
-static void reply_called_name_not_present(char *outbuf)
-{
-       smb_setlen(outbuf, 1);
-       SCVAL(outbuf, 0, 0x83);
-       SCVAL(outbuf, 4, 0x82);
-}
-
-/****************************************************************************
- Reply to a (netbios-level) special message. 
-****************************************************************************/
-
-void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
-{
-       struct smbd_server_connection *sconn = xconn->client->sconn;
-       int msg_type = CVAL(inbuf,0);
-       int msg_flags = CVAL(inbuf,1);
-       /*
-        * We only really use 4 bytes of the outbuf, but for the smb_setlen
-        * calculation & friends (srv_send_smb uses that) we need the full smb
-        * header.
-        */
-       char outbuf[smb_size];
-
-       memset(outbuf, '\0', sizeof(outbuf));
-
-       smb_setlen(outbuf,0);
-
-       switch (msg_type) {
-       case NBSSrequest: /* session request */
-       {
-               /* inbuf_size is guarenteed to be at least 4. */
-               fstring name1,name2;
-               int name_type1, name_type2;
-               int name_len1, name_len2;
-
-               *name1 = *name2 = 0;
-
-               if (xconn->transport.nbt.got_session) {
-                       exit_server_cleanly("multiple session request not permitted");
-               }
-
-               SCVAL(outbuf,0,NBSSpositive);
-               SCVAL(outbuf,3,0);
-
-               /* inbuf_size is guaranteed to be at least 4. */
-               name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
-               if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
-                       DEBUG(0,("Invalid name length in session request\n"));
-                       reply_called_name_not_present(outbuf);
-                       break;
-               }
-               name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
-               if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
-                       DEBUG(0,("Invalid name length in session request\n"));
-                       reply_called_name_not_present(outbuf);
-                       break;
-               }
-
-               name_type1 = name_extract((unsigned char *)inbuf,
-                               inbuf_size,(unsigned int)4,name1);
-               name_type2 = name_extract((unsigned char *)inbuf,
-                               inbuf_size,(unsigned int)(4 + name_len1),name2);
-
-               if (name_type1 == -1 || name_type2 == -1) {
-                       DEBUG(0,("Invalid name type in session request\n"));
-                       reply_called_name_not_present(outbuf);
-                       break;
-               }
-
-               DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
-                        name1, name_type1, name2, name_type2));
-
-               if (netbios_session_retarget(xconn, name1, name_type1)) {
-                       exit_server_cleanly("retargeted client");
-               }
-
-               /*
-                * Windows NT/2k uses "*SMBSERVER" and XP uses
-                * "*SMBSERV" arrggg!!!
-                */
-               if (strequal(name1, "*SMBSERVER     ")
-                   || strequal(name1, "*SMBSERV       "))  {
-                       char *raddr;
-
-                       raddr = tsocket_address_inet_addr_string(sconn->remote_address,
-                                                                talloc_tos());
-                       if (raddr == NULL) {
-                               exit_server_cleanly("could not allocate raddr");
-                       }
-
-                       fstrcpy(name1, raddr);
-               }
-
-               set_local_machine_name(name1, True);
-               set_remote_machine_name(name2, True);
-
-               if (is_ipaddress(sconn->remote_hostname)) {
-                       char *p = discard_const_p(char, sconn->remote_hostname);
-
-                       talloc_free(p);
-
-                       sconn->remote_hostname = talloc_strdup(sconn,
-                                               get_remote_machine_name());
-                       if (sconn->remote_hostname == NULL) {
-                               exit_server_cleanly("could not copy remote name");
-                       }
-                       xconn->remote_hostname = sconn->remote_hostname;
-               }
-
-               DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
-                        get_local_machine_name(), get_remote_machine_name(),
-                        name_type2));
-
-               if (name_type2 == 'R') {
-                       /* We are being asked for a pathworks session --- 
-                          no thanks! */
-                       reply_called_name_not_present(outbuf);
-                       break;
-               }
-
-               reload_services(sconn, conn_snum_used, true);
-               reopen_logs();
-
-               xconn->transport.nbt.got_session = true;
-               break;
-       }
-
-       case 0x89: /* session keepalive request 
-                     (some old clients produce this?) */
-               SCVAL(outbuf,0,NBSSkeepalive);
-               SCVAL(outbuf,3,0);
-               break;
-
-       case NBSSpositive: /* positive session response */
-       case NBSSnegative: /* negative session response */
-       case NBSSretarget: /* retarget session response */
-               DEBUG(0,("Unexpected session response\n"));
-               break;
-
-       case NBSSkeepalive: /* session keepalive */
-       default:
-               return;
-       }
-
-       DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
-                   msg_type, msg_flags));
-
-       if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
-               exit_server_cleanly("reply_special: srv_send_smb failed.");
-       }
-
-       if (CVAL(outbuf, 0) != 0x82) {
-               exit_server_cleanly("invalid netbios session");
-       }
-       return;
-}
-
 /****************************************************************************
  Reply to a tcon.
  conn POINTER CAN BE NULL HERE !
index 8cfbde2dd4564538807f442b970de1ecc24032aa..fda1b8a9ac9a8ea9af55200063ee0ad620b17685 100644 (file)
@@ -461,3 +461,284 @@ bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
 
        return true;
 }
+
+/****************************************************************************
+ Return the port number we've bound to on a socket.
+****************************************************************************/
+
+static int get_socket_port(int fd)
+{
+       struct samba_sockaddr saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
+
+       if (fd == -1) {
+               return -1;
+       }
+
+       if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
+               int level = (errno == ENOTCONN) ? 2 : 0;
+               DEBUG(level, ("getsockname failed. Error was %s\n",
+                              strerror(errno)));
+               return -1;
+       }
+
+#if defined(HAVE_IPV6)
+       if (saddr.u.sa.sa_family == AF_INET6) {
+               return ntohs(saddr.u.in6.sin6_port);
+       }
+#endif
+       if (saddr.u.sa.sa_family == AF_INET) {
+               return ntohs(saddr.u.in.sin_port);
+       }
+       return -1;
+}
+
+static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
+                                    const char *name, int name_type)
+{
+       char *trim_name;
+       char *trim_name_type;
+       const char *retarget_parm;
+       char *retarget;
+       char *p;
+       int retarget_type = 0x20;
+       int retarget_port = NBT_SMB_PORT;
+       struct sockaddr_storage retarget_addr;
+       struct sockaddr_in *in_addr;
+       bool ret = false;
+       uint8_t outbuf[10];
+
+       if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
+               return false;
+       }
+
+       trim_name = talloc_strdup(talloc_tos(), name);
+       if (trim_name == NULL) {
+               goto fail;
+       }
+       trim_char(trim_name, ' ', ' ');
+
+       trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
+                                        name_type);
+       if (trim_name_type == NULL) {
+               goto fail;
+       }
+
+       retarget_parm = lp_parm_const_string(-1, "netbios retarget",
+                                            trim_name_type, NULL);
+       if (retarget_parm == NULL) {
+               retarget_parm = lp_parm_const_string(-1, "netbios retarget",
+                                                    trim_name, NULL);
+       }
+       if (retarget_parm == NULL) {
+               goto fail;
+       }
+
+       retarget = talloc_strdup(trim_name, retarget_parm);
+       if (retarget == NULL) {
+               goto fail;
+       }
+
+       DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
+
+       p = strchr(retarget, ':');
+       if (p != NULL) {
+               *p++ = '\0';
+               retarget_port = atoi(p);
+       }
+
+       p = strchr_m(retarget, '#');
+       if (p != NULL) {
+               *p++ = '\0';
+               if (sscanf(p, "%x", &retarget_type) != 1) {
+                       goto fail;
+               }
+       }
+
+       ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
+       if (!ret) {
+               DEBUG(10, ("could not resolve %s\n", retarget));
+               goto fail;
+       }
+
+       if (retarget_addr.ss_family != AF_INET) {
+               DEBUG(10, ("Retarget target not an IPv4 addr\n"));
+               goto fail;
+       }
+
+       in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
+
+       _smb_setlen(outbuf, 6);
+       SCVAL(outbuf, 0, 0x84);
+       *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
+       *(uint16_t *)(outbuf+8) = htons(retarget_port);
+
+       if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
+                         NULL)) {
+               exit_server_cleanly("netbios_session_retarget: srv_send_smb "
+                                   "failed.");
+       }
+
+       ret = true;
+ fail:
+       TALLOC_FREE(trim_name);
+       return ret;
+}
+
+static void reply_called_name_not_present(char *outbuf)
+{
+       smb_setlen(outbuf, 1);
+       SCVAL(outbuf, 0, 0x83);
+       SCVAL(outbuf, 4, 0x82);
+}
+
+/****************************************************************************
+ Reply to a (netbios-level) special message.
+****************************************************************************/
+
+void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
+{
+       struct smbd_server_connection *sconn = xconn->client->sconn;
+       int msg_type = CVAL(inbuf,0);
+       int msg_flags = CVAL(inbuf,1);
+       /*
+        * We only really use 4 bytes of the outbuf, but for the smb_setlen
+        * calculation & friends (srv_send_smb uses that) we need the full smb
+        * header.
+        */
+       char outbuf[smb_size];
+
+       memset(outbuf, '\0', sizeof(outbuf));
+
+       smb_setlen(outbuf,0);
+
+       switch (msg_type) {
+       case NBSSrequest: /* session request */
+       {
+               /* inbuf_size is guarenteed to be at least 4. */
+               fstring name1,name2;
+               int name_type1, name_type2;
+               int name_len1, name_len2;
+
+               *name1 = *name2 = 0;
+
+               if (xconn->transport.nbt.got_session) {
+                       exit_server_cleanly("multiple session request not permitted");
+               }
+
+               SCVAL(outbuf,0,NBSSpositive);
+               SCVAL(outbuf,3,0);
+
+               /* inbuf_size is guaranteed to be at least 4. */
+               name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
+               if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
+                       DEBUG(0,("Invalid name length in session request\n"));
+                       reply_called_name_not_present(outbuf);
+                       break;
+               }
+               name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
+               if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
+                       DEBUG(0,("Invalid name length in session request\n"));
+                       reply_called_name_not_present(outbuf);
+                       break;
+               }
+
+               name_type1 = name_extract((unsigned char *)inbuf,
+                               inbuf_size,(unsigned int)4,name1);
+               name_type2 = name_extract((unsigned char *)inbuf,
+                               inbuf_size,(unsigned int)(4 + name_len1),name2);
+
+               if (name_type1 == -1 || name_type2 == -1) {
+                       DEBUG(0,("Invalid name type in session request\n"));
+                       reply_called_name_not_present(outbuf);
+                       break;
+               }
+
+               DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
+                        name1, name_type1, name2, name_type2));
+
+               if (netbios_session_retarget(xconn, name1, name_type1)) {
+                       exit_server_cleanly("retargeted client");
+               }
+
+               /*
+                * Windows NT/2k uses "*SMBSERVER" and XP uses
+                * "*SMBSERV" arrggg!!!
+                */
+               if (strequal(name1, "*SMBSERVER     ")
+                   || strequal(name1, "*SMBSERV       "))  {
+                       char *raddr;
+
+                       raddr = tsocket_address_inet_addr_string(sconn->remote_address,
+                                                                talloc_tos());
+                       if (raddr == NULL) {
+                               exit_server_cleanly("could not allocate raddr");
+                       }
+
+                       fstrcpy(name1, raddr);
+               }
+
+               set_local_machine_name(name1, True);
+               set_remote_machine_name(name2, True);
+
+               if (is_ipaddress(sconn->remote_hostname)) {
+                       char *p = discard_const_p(char, sconn->remote_hostname);
+
+                       talloc_free(p);
+
+                       sconn->remote_hostname = talloc_strdup(sconn,
+                                               get_remote_machine_name());
+                       if (sconn->remote_hostname == NULL) {
+                               exit_server_cleanly("could not copy remote name");
+                       }
+                       xconn->remote_hostname = sconn->remote_hostname;
+               }
+
+               DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
+                        get_local_machine_name(), get_remote_machine_name(),
+                        name_type2));
+
+               if (name_type2 == 'R') {
+                       /* We are being asked for a pathworks session ---
+                          no thanks! */
+                       reply_called_name_not_present(outbuf);
+                       break;
+               }
+
+               reload_services(sconn, conn_snum_used, true);
+               reopen_logs();
+
+               xconn->transport.nbt.got_session = true;
+               break;
+       }
+
+       case 0x89: /* session keepalive request
+                     (some old clients produce this?) */
+               SCVAL(outbuf,0,NBSSkeepalive);
+               SCVAL(outbuf,3,0);
+               break;
+
+       case NBSSpositive: /* positive session response */
+       case NBSSnegative: /* negative session response */
+       case NBSSretarget: /* retarget session response */
+               DEBUG(0,("Unexpected session response\n"));
+               break;
+
+       case NBSSkeepalive: /* session keepalive */
+       default:
+               return;
+       }
+
+       DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
+                   msg_type, msg_flags));
+
+       if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
+               exit_server_cleanly("reply_special: srv_send_smb failed.");
+       }
+
+       if (CVAL(outbuf, 0) != 0x82) {
+               exit_server_cleanly("invalid netbios session");
+       }
+       return;
+}