1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

smbd: Move reply_special to smb2_reply.c

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
David Mulder 2022-03-17 11:04:28 -06:00 committed by Jeremy Allison
parent f0396b9af9
commit 95d9606827
3 changed files with 282 additions and 282 deletions

View 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 */

View File

@ -53,287 +53,6 @@
#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 !

View 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;
}