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:
parent
f0396b9af9
commit
95d9606827
@ -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 */
|
||||
|
||||
|
@ -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 !
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user