mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
smbd: Move smbd_add_connection to smb2_process.c
Signed-off-by: David Mulder <dmulder@suse.com> Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
parent
c43c9ef3ee
commit
6f792afe43
@ -66,7 +66,7 @@ struct pending_message_list {
|
|||||||
|
|
||||||
static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf);
|
static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf);
|
||||||
|
|
||||||
static void smbd_echo_init(struct smbXsrv_connection *xconn)
|
void smbd_echo_init(struct smbXsrv_connection *xconn)
|
||||||
{
|
{
|
||||||
xconn->smb1.echo_handler.trusted_fd = -1;
|
xconn->smb1.echo_handler.trusted_fd = -1;
|
||||||
xconn->smb1.echo_handler.socket_lock_fd = -1;
|
xconn->smb1.echo_handler.socket_lock_fd = -1;
|
||||||
@ -1414,7 +1414,7 @@ static connection_struct *switch_message(uint8_t type, struct smb_request *req)
|
|||||||
Construct a reply to the incoming packet.
|
Construct a reply to the incoming packet.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void construct_reply(struct smbXsrv_connection *xconn,
|
void construct_reply(struct smbXsrv_connection *xconn,
|
||||||
char *inbuf, int size, size_t unread_bytes,
|
char *inbuf, int size, size_t unread_bytes,
|
||||||
uint32_t seqnum, bool encrypted,
|
uint32_t seqnum, bool encrypted,
|
||||||
struct smb_perfcount_data *deferred_pcd)
|
struct smb_perfcount_data *deferred_pcd)
|
||||||
@ -2150,126 +2150,8 @@ static void smbd_server_connection_write_handler(
|
|||||||
/* TODO: make write nonblocking */
|
/* TODO: make write nonblocking */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smbd_smb2_server_connection_read_handler(
|
void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
|
||||||
struct smbXsrv_connection *xconn, int fd)
|
int fd)
|
||||||
{
|
|
||||||
char lenbuf[NBT_HDR_SIZE];
|
|
||||||
size_t len = 0;
|
|
||||||
uint8_t *buffer = NULL;
|
|
||||||
size_t bufferlen = 0;
|
|
||||||
NTSTATUS status;
|
|
||||||
uint8_t msg_type = 0;
|
|
||||||
|
|
||||||
/* Read the first 4 bytes - contains length of remainder. */
|
|
||||||
status = read_smb_length_return_keepalive(fd, lenbuf, 0, &len);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
exit_server_cleanly("failed to receive request length");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Integer wrap check. */
|
|
||||||
if (len + NBT_HDR_SIZE < len) {
|
|
||||||
exit_server_cleanly("Invalid length on initial request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The +4 here can't wrap, we've checked the length above already.
|
|
||||||
*/
|
|
||||||
bufferlen = len+NBT_HDR_SIZE;
|
|
||||||
|
|
||||||
buffer = talloc_array(talloc_tos(), uint8_t, bufferlen);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
DBG_ERR("Could not allocate request inbuf of length %zu\n",
|
|
||||||
bufferlen);
|
|
||||||
exit_server_cleanly("talloc fail");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the NBT_HDR_SIZE length. */
|
|
||||||
memcpy(buffer, lenbuf, sizeof(lenbuf));
|
|
||||||
|
|
||||||
status = read_packet_remainder(fd, (char *)buffer+NBT_HDR_SIZE, 0, len);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
exit_server_cleanly("Failed to read remainder of initial request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the message type. */
|
|
||||||
msg_type = PULL_LE_U8(buffer,0);
|
|
||||||
if (msg_type == NBSSrequest) {
|
|
||||||
/*
|
|
||||||
* clients can send this request before
|
|
||||||
* bootstrapping into SMB2. Cope with this
|
|
||||||
* message only, don't allow any other strange
|
|
||||||
* NBSS types.
|
|
||||||
*/
|
|
||||||
reply_special(xconn, (char *)buffer, bufferlen);
|
|
||||||
xconn->client->sconn->num_requests++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only a 'normal' message type allowed now. */
|
|
||||||
if (msg_type != NBSSmessage) {
|
|
||||||
DBG_ERR("Invalid message type %d\n", msg_type);
|
|
||||||
exit_server_cleanly("Invalid message type for initial request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Could this be an SMB1 negprot bootstrap into SMB2 ? */
|
|
||||||
if (bufferlen < smb_size) {
|
|
||||||
exit_server_cleanly("Invalid initial SMB1 or SMB2 packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if defined(WITH_SMB1SERVER)
|
|
||||||
if (valid_smb_header(buffer)) {
|
|
||||||
/* Can *only* allow an SMB1 negprot here. */
|
|
||||||
uint8_t cmd = PULL_LE_U8(buffer, smb_com);
|
|
||||||
if (cmd != SMBnegprot) {
|
|
||||||
DBG_ERR("Incorrect SMB1 command 0x%hhx, "
|
|
||||||
"should be SMBnegprot (0x72)\n",
|
|
||||||
cmd);
|
|
||||||
exit_server_cleanly("Invalid initial SMB1 packet");
|
|
||||||
}
|
|
||||||
/* Minimal process_smb(). */
|
|
||||||
show_msg((char *)buffer);
|
|
||||||
construct_reply(xconn,
|
|
||||||
(char *)buffer,
|
|
||||||
bufferlen,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
NULL);
|
|
||||||
xconn->client->sconn->trans_num++;
|
|
||||||
xconn->client->sconn->num_requests++;
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (!smbd_is_smb2_header(buffer, bufferlen)) {
|
|
||||||
exit_server_cleanly("Invalid initial SMB2 packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here we know we're a valid SMB2 packet. */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Point at the start of the SMB2 PDU.
|
|
||||||
* len is the length of the SMB2 PDU.
|
|
||||||
*/
|
|
||||||
|
|
||||||
status = smbd_smb2_process_negprot(xconn,
|
|
||||||
0,
|
|
||||||
(const uint8_t *)buffer+NBT_HDR_SIZE,
|
|
||||||
len);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
exit_server_cleanly("SMB2 negprot fail");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void smbd_smb1_server_connection_read_handler(
|
|
||||||
struct smbXsrv_connection *xconn, int fd)
|
|
||||||
{
|
{
|
||||||
uint8_t *inbuf = NULL;
|
uint8_t *inbuf = NULL;
|
||||||
size_t inbuf_len = 0;
|
size_t inbuf_len = 0;
|
||||||
@ -2333,44 +2215,6 @@ process:
|
|||||||
seqnum, encrypted, NULL);
|
seqnum, encrypted, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smbd_server_connection_handler(struct tevent_context *ev,
|
|
||||||
struct tevent_fd *fde,
|
|
||||||
uint16_t flags,
|
|
||||||
void *private_data)
|
|
||||||
{
|
|
||||||
struct smbXsrv_connection *xconn =
|
|
||||||
talloc_get_type_abort(private_data,
|
|
||||||
struct smbXsrv_connection);
|
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(xconn->transport.status)) {
|
|
||||||
/*
|
|
||||||
* we're not supposed to do any io
|
|
||||||
*/
|
|
||||||
TEVENT_FD_NOT_READABLE(xconn->transport.fde);
|
|
||||||
TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & TEVENT_FD_WRITE) {
|
|
||||||
smbd_server_connection_write_handler(xconn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (flags & TEVENT_FD_READ) {
|
|
||||||
#if defined(WITH_SMB1SERVER)
|
|
||||||
if (lp_server_min_protocol() > PROTOCOL_NT1) {
|
|
||||||
#endif
|
|
||||||
smbd_smb2_server_connection_read_handler(xconn,
|
|
||||||
xconn->transport.sock);
|
|
||||||
#if defined(WITH_SMB1SERVER)
|
|
||||||
} else {
|
|
||||||
smbd_smb1_server_connection_read_handler(xconn,
|
|
||||||
xconn->transport.sock);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void smbd_server_echo_handler(struct tevent_context *ev,
|
static void smbd_server_echo_handler(struct tevent_context *ev,
|
||||||
struct tevent_fd *fde,
|
struct tevent_fd *fde,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
@ -2400,180 +2244,6 @@ static void smbd_server_echo_handler(struct tevent_context *ev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct smbd_release_ip_state {
|
|
||||||
struct smbXsrv_connection *xconn;
|
|
||||||
struct tevent_immediate *im;
|
|
||||||
char addr[INET6_ADDRSTRLEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void smbd_release_ip_immediate(struct tevent_context *ctx,
|
|
||||||
struct tevent_immediate *im,
|
|
||||||
void *private_data)
|
|
||||||
{
|
|
||||||
struct smbd_release_ip_state *state =
|
|
||||||
talloc_get_type_abort(private_data,
|
|
||||||
struct smbd_release_ip_state);
|
|
||||||
struct smbXsrv_connection *xconn = state->xconn;
|
|
||||||
|
|
||||||
if (!NT_STATUS_EQUAL(xconn->transport.status, NT_STATUS_ADDRESS_CLOSED)) {
|
|
||||||
/*
|
|
||||||
* smbd_server_connection_terminate() already triggered ?
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
smbd_server_connection_terminate(xconn, "CTDB_SRVID_RELEASE_IP");
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
received when we should release a specific IP
|
|
||||||
****************************************************************************/
|
|
||||||
static int release_ip(struct tevent_context *ev,
|
|
||||||
uint32_t src_vnn, uint32_t dst_vnn,
|
|
||||||
uint64_t dst_srvid,
|
|
||||||
const uint8_t *msg, size_t msglen,
|
|
||||||
void *private_data)
|
|
||||||
{
|
|
||||||
struct smbd_release_ip_state *state =
|
|
||||||
talloc_get_type_abort(private_data,
|
|
||||||
struct smbd_release_ip_state);
|
|
||||||
struct smbXsrv_connection *xconn = state->xconn;
|
|
||||||
const char *ip;
|
|
||||||
const char *addr = state->addr;
|
|
||||||
const char *p = addr;
|
|
||||||
|
|
||||||
if (msglen == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (msg[msglen-1] != '\0') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip = (const char *)msg;
|
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(xconn->transport.status)) {
|
|
||||||
/* avoid recursion */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp("::ffff:", addr, 7) == 0) {
|
|
||||||
p = addr + 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("Got release IP message for %s, "
|
|
||||||
"our address is %s\n", ip, p));
|
|
||||||
|
|
||||||
if ((strcmp(p, ip) == 0) || ((p != addr) && strcmp(addr, ip) == 0)) {
|
|
||||||
DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
|
|
||||||
ip));
|
|
||||||
/*
|
|
||||||
* With SMB2 we should do a clean disconnect,
|
|
||||||
* the previous_session_id in the session setup
|
|
||||||
* will cleanup the old session, tcons and opens.
|
|
||||||
*
|
|
||||||
* A clean disconnect is needed in order to support
|
|
||||||
* durable handles.
|
|
||||||
*
|
|
||||||
* Note: typically this is never triggered
|
|
||||||
* as we got a TCP RST (triggered by ctdb event scripts)
|
|
||||||
* before we get CTDB_SRVID_RELEASE_IP.
|
|
||||||
*
|
|
||||||
* We used to call _exit(1) here, but as this was mostly never
|
|
||||||
* triggered and has implication on our process model,
|
|
||||||
* we can just use smbd_server_connection_terminate()
|
|
||||||
* (also for SMB1).
|
|
||||||
*
|
|
||||||
* We don't call smbd_server_connection_terminate() directly
|
|
||||||
* as we might be called from within ctdbd_migrate(),
|
|
||||||
* we need to defer our action to the next event loop
|
|
||||||
*/
|
|
||||||
tevent_schedule_immediate(state->im,
|
|
||||||
xconn->client->raw_ev_ctx,
|
|
||||||
smbd_release_ip_immediate,
|
|
||||||
state);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure we don't get any io on the connection.
|
|
||||||
*/
|
|
||||||
xconn->transport.status = NT_STATUS_ADDRESS_CLOSED;
|
|
||||||
return EADDRNOTAVAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int match_cluster_movable_ip(uint32_t total_ip_count,
|
|
||||||
const struct sockaddr_storage *ip,
|
|
||||||
bool is_movable_ip,
|
|
||||||
void *private_data)
|
|
||||||
{
|
|
||||||
const struct sockaddr_storage *srv = private_data;
|
|
||||||
struct samba_sockaddr pub_ip = {
|
|
||||||
.u = {
|
|
||||||
.ss = *ip,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
struct samba_sockaddr srv_ip = {
|
|
||||||
.u = {
|
|
||||||
.ss = *srv,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (is_movable_ip && sockaddr_equal(&pub_ip.u.sa, &srv_ip.u.sa)) {
|
|
||||||
return EADDRNOTAVAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
|
|
||||||
struct sockaddr_storage *srv,
|
|
||||||
struct sockaddr_storage *clnt)
|
|
||||||
{
|
|
||||||
struct smbd_release_ip_state *state;
|
|
||||||
struct ctdbd_connection *cconn;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
cconn = messaging_ctdb_connection();
|
|
||||||
if (cconn == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = talloc_zero(xconn, struct smbd_release_ip_state);
|
|
||||||
if (state == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
state->xconn = xconn;
|
|
||||||
state->im = tevent_create_immediate(state);
|
|
||||||
if (state->im == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
if (print_sockaddr(state->addr, sizeof(state->addr), srv) == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xconn->client->server_multi_channel_enabled) {
|
|
||||||
ret = ctdbd_public_ip_foreach(cconn,
|
|
||||||
match_cluster_movable_ip,
|
|
||||||
srv);
|
|
||||||
if (ret == EADDRNOTAVAIL) {
|
|
||||||
xconn->has_cluster_movable_ip = true;
|
|
||||||
DBG_DEBUG("cluster movable IP on %s\n",
|
|
||||||
smbXsrv_connection_dbg(xconn));
|
|
||||||
} else if (ret != 0) {
|
|
||||||
DBG_ERR("failed to iterate cluster IPs: %s\n",
|
|
||||||
strerror(ret));
|
|
||||||
return NT_STATUS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
|
|
||||||
if (ret != 0) {
|
|
||||||
return map_nt_error_from_unix(ret);
|
|
||||||
}
|
|
||||||
return NT_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msg_kill_client_ip(struct messaging_context *msg_ctx,
|
static void msg_kill_client_ip(struct messaging_context *msg_ctx,
|
||||||
void *private_data, uint32_t msg_type,
|
void *private_data, uint32_t msg_type,
|
||||||
struct server_id server_id, DATA_BLOB *data)
|
struct server_id server_id, DATA_BLOB *data)
|
||||||
@ -3411,223 +3081,6 @@ static void smbd_tevent_trace_callback(enum tevent_trace_point point,
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smbXsrv_connection_destructor(struct smbXsrv_connection *xconn)
|
|
||||||
{
|
|
||||||
DBG_DEBUG("xconn[%s]\n", smbXsrv_connection_dbg(xconn));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
|
|
||||||
NTTIME now, struct smbXsrv_connection **_xconn)
|
|
||||||
{
|
|
||||||
TALLOC_CTX *frame = talloc_stackframe();
|
|
||||||
struct smbXsrv_connection *xconn;
|
|
||||||
struct sockaddr_storage ss_srv;
|
|
||||||
void *sp_srv = (void *)&ss_srv;
|
|
||||||
struct sockaddr *sa_srv = (struct sockaddr *)sp_srv;
|
|
||||||
struct sockaddr_storage ss_clnt;
|
|
||||||
void *sp_clnt = (void *)&ss_clnt;
|
|
||||||
struct sockaddr *sa_clnt = (struct sockaddr *)sp_clnt;
|
|
||||||
socklen_t sa_socklen;
|
|
||||||
struct tsocket_address *local_address = NULL;
|
|
||||||
struct tsocket_address *remote_address = NULL;
|
|
||||||
const char *remaddr = NULL;
|
|
||||||
char *p;
|
|
||||||
const char *rhost = NULL;
|
|
||||||
int ret;
|
|
||||||
int tmp;
|
|
||||||
|
|
||||||
*_xconn = NULL;
|
|
||||||
|
|
||||||
DO_PROFILE_INC(connect);
|
|
||||||
|
|
||||||
xconn = talloc_zero(client, struct smbXsrv_connection);
|
|
||||||
if (xconn == NULL) {
|
|
||||||
DEBUG(0,("talloc_zero(struct smbXsrv_connection)\n"));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
talloc_set_destructor(xconn, smbXsrv_connection_destructor);
|
|
||||||
talloc_steal(frame, xconn);
|
|
||||||
xconn->client = client;
|
|
||||||
xconn->connect_time = now;
|
|
||||||
if (client->next_channel_id != 0) {
|
|
||||||
xconn->channel_id = client->next_channel_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
xconn->transport.sock = sock_fd;
|
|
||||||
#if defined(WITH_SMB1SERVER)
|
|
||||||
smbd_echo_init(xconn);
|
|
||||||
#endif
|
|
||||||
xconn->protocol = PROTOCOL_NONE;
|
|
||||||
|
|
||||||
/* Ensure child is set to blocking mode */
|
|
||||||
set_blocking(sock_fd,True);
|
|
||||||
|
|
||||||
set_socket_options(sock_fd, "SO_KEEPALIVE");
|
|
||||||
set_socket_options(sock_fd, lp_socket_options());
|
|
||||||
|
|
||||||
sa_socklen = sizeof(ss_clnt);
|
|
||||||
ret = getpeername(sock_fd, sa_clnt, &sa_socklen);
|
|
||||||
if (ret != 0) {
|
|
||||||
int saved_errno = errno;
|
|
||||||
int level = (errno == ENOTCONN)?2:0;
|
|
||||||
DEBUG(level,("getpeername() failed - %s\n",
|
|
||||||
strerror(saved_errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return map_nt_error_from_unix_common(saved_errno);
|
|
||||||
}
|
|
||||||
ret = tsocket_address_bsd_from_sockaddr(xconn,
|
|
||||||
sa_clnt, sa_socklen,
|
|
||||||
&remote_address);
|
|
||||||
if (ret != 0) {
|
|
||||||
int saved_errno = errno;
|
|
||||||
DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
|
|
||||||
__location__, strerror(saved_errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return map_nt_error_from_unix_common(saved_errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
sa_socklen = sizeof(ss_srv);
|
|
||||||
ret = getsockname(sock_fd, sa_srv, &sa_socklen);
|
|
||||||
if (ret != 0) {
|
|
||||||
int saved_errno = errno;
|
|
||||||
int level = (errno == ENOTCONN)?2:0;
|
|
||||||
DEBUG(level,("getsockname() failed - %s\n",
|
|
||||||
strerror(saved_errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return map_nt_error_from_unix_common(saved_errno);
|
|
||||||
}
|
|
||||||
ret = tsocket_address_bsd_from_sockaddr(xconn,
|
|
||||||
sa_srv, sa_socklen,
|
|
||||||
&local_address);
|
|
||||||
if (ret != 0) {
|
|
||||||
int saved_errno = errno;
|
|
||||||
DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
|
|
||||||
__location__, strerror(saved_errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return map_nt_error_from_unix_common(saved_errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tsocket_address_is_inet(remote_address, "ip")) {
|
|
||||||
remaddr = tsocket_address_inet_addr_string(remote_address,
|
|
||||||
talloc_tos());
|
|
||||||
if (remaddr == NULL) {
|
|
||||||
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
|
|
||||||
__location__, strerror(errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
remaddr = "0.0.0.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Before the first packet, check the global hosts allow/ hosts deny
|
|
||||||
* parameters before doing any parsing of packets passed to us by the
|
|
||||||
* client. This prevents attacks on our parsing code from hosts not in
|
|
||||||
* the hosts allow list.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = get_remote_hostname(remote_address,
|
|
||||||
&p, talloc_tos());
|
|
||||||
if (ret < 0) {
|
|
||||||
int saved_errno = errno;
|
|
||||||
DEBUG(0,("%s: get_remote_hostname failed - %s\n",
|
|
||||||
__location__, strerror(saved_errno)));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return map_nt_error_from_unix_common(saved_errno);
|
|
||||||
}
|
|
||||||
rhost = p;
|
|
||||||
if (strequal(rhost, "UNKNOWN")) {
|
|
||||||
rhost = remaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
xconn->local_address = local_address;
|
|
||||||
xconn->remote_address = remote_address;
|
|
||||||
xconn->remote_hostname = talloc_strdup(xconn, rhost);
|
|
||||||
if (xconn->remote_hostname == NULL) {
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!srv_init_signing(xconn)) {
|
|
||||||
DEBUG(0, ("Failed to init smb_signing\n"));
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1),
|
|
||||||
xconn->remote_hostname,
|
|
||||||
remaddr)) {
|
|
||||||
DEBUG( 1, ("Connection denied from %s to %s\n",
|
|
||||||
tsocket_address_string(remote_address, talloc_tos()),
|
|
||||||
tsocket_address_string(local_address, talloc_tos())));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We return a valid xconn
|
|
||||||
* so that the caller can return an error message
|
|
||||||
* to the client
|
|
||||||
*/
|
|
||||||
DLIST_ADD_END(client->connections, xconn);
|
|
||||||
talloc_steal(client, xconn);
|
|
||||||
|
|
||||||
*_xconn = xconn;
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_NETWORK_ACCESS_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("Connection allowed from %s to %s\n",
|
|
||||||
tsocket_address_string(remote_address, talloc_tos()),
|
|
||||||
tsocket_address_string(local_address, talloc_tos())));
|
|
||||||
|
|
||||||
if (lp_clustering()) {
|
|
||||||
/*
|
|
||||||
* We need to tell ctdb about our client's TCP
|
|
||||||
* connection, so that for failover ctdbd can send
|
|
||||||
* tickle acks, triggering a reconnection by the
|
|
||||||
* client.
|
|
||||||
*/
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
status = smbd_register_ips(xconn, &ss_srv, &ss_clnt);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
DEBUG(0, ("ctdbd_register_ips failed: %s\n",
|
|
||||||
nt_errstr(status)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = lp_max_xmit();
|
|
||||||
tmp = MAX(tmp, SMB_BUFFER_SIZE_MIN);
|
|
||||||
tmp = MIN(tmp, SMB_BUFFER_SIZE_MAX);
|
|
||||||
|
|
||||||
#if defined(WITH_SMB1SERVER)
|
|
||||||
xconn->smb1.negprot.max_recv = tmp;
|
|
||||||
|
|
||||||
xconn->smb1.sessions.done_sesssetup = false;
|
|
||||||
xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xconn->transport.fde = tevent_add_fd(client->raw_ev_ctx,
|
|
||||||
xconn,
|
|
||||||
sock_fd,
|
|
||||||
TEVENT_FD_READ,
|
|
||||||
smbd_server_connection_handler,
|
|
||||||
xconn);
|
|
||||||
if (!xconn->transport.fde) {
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
tevent_fd_set_auto_close(xconn->transport.fde);
|
|
||||||
|
|
||||||
/* for now we only have one connection */
|
|
||||||
DLIST_ADD_END(client->connections, xconn);
|
|
||||||
talloc_steal(client, xconn);
|
|
||||||
|
|
||||||
*_xconn = xconn;
|
|
||||||
TALLOC_FREE(frame);
|
|
||||||
return NT_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Process commands from the client
|
Process commands from the client
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -892,6 +892,13 @@ void process_smb1(struct smbXsrv_connection *xconn,
|
|||||||
uint32_t seqnum, bool encrypted,
|
uint32_t seqnum, bool encrypted,
|
||||||
struct smb_perfcount_data *deferred_pcd);
|
struct smb_perfcount_data *deferred_pcd);
|
||||||
bool valid_smb_header(const uint8_t *inbuf);
|
bool valid_smb_header(const uint8_t *inbuf);
|
||||||
|
void smbd_echo_init(struct smbXsrv_connection *xconn);
|
||||||
|
void construct_reply(struct smbXsrv_connection *xconn,
|
||||||
|
char *inbuf, int size, size_t unread_bytes,
|
||||||
|
uint32_t seqnum, bool encrypted,
|
||||||
|
struct smb_perfcount_data *deferred_pcd);
|
||||||
|
void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
|
||||||
|
int fd);
|
||||||
|
|
||||||
/* The following definitions come from smbd/smb2_process.c */
|
/* The following definitions come from smbd/smb2_process.c */
|
||||||
|
|
||||||
|
@ -731,3 +731,556 @@ const char *smbXsrv_connection_dbg(const struct smbXsrv_connection *xconn)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void smbd_server_connection_write_handler(
|
||||||
|
struct smbXsrv_connection *xconn)
|
||||||
|
{
|
||||||
|
/* TODO: make write nonblocking */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbd_smb2_server_connection_read_handler(
|
||||||
|
struct smbXsrv_connection *xconn, int fd)
|
||||||
|
{
|
||||||
|
char lenbuf[NBT_HDR_SIZE];
|
||||||
|
size_t len = 0;
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
size_t bufferlen = 0;
|
||||||
|
NTSTATUS status;
|
||||||
|
uint8_t msg_type = 0;
|
||||||
|
|
||||||
|
/* Read the first 4 bytes - contains length of remainder. */
|
||||||
|
status = read_smb_length_return_keepalive(fd, lenbuf, 0, &len);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
exit_server_cleanly("failed to receive request length");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Integer wrap check. */
|
||||||
|
if (len + NBT_HDR_SIZE < len) {
|
||||||
|
exit_server_cleanly("Invalid length on initial request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The +4 here can't wrap, we've checked the length above already.
|
||||||
|
*/
|
||||||
|
bufferlen = len+NBT_HDR_SIZE;
|
||||||
|
|
||||||
|
buffer = talloc_array(talloc_tos(), uint8_t, bufferlen);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
DBG_ERR("Could not allocate request inbuf of length %zu\n",
|
||||||
|
bufferlen);
|
||||||
|
exit_server_cleanly("talloc fail");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the NBT_HDR_SIZE length. */
|
||||||
|
memcpy(buffer, lenbuf, sizeof(lenbuf));
|
||||||
|
|
||||||
|
status = read_packet_remainder(fd, (char *)buffer+NBT_HDR_SIZE, 0, len);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
exit_server_cleanly("Failed to read remainder of initial request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the message type. */
|
||||||
|
msg_type = PULL_LE_U8(buffer,0);
|
||||||
|
if (msg_type == NBSSrequest) {
|
||||||
|
/*
|
||||||
|
* clients can send this request before
|
||||||
|
* bootstrapping into SMB2. Cope with this
|
||||||
|
* message only, don't allow any other strange
|
||||||
|
* NBSS types.
|
||||||
|
*/
|
||||||
|
reply_special(xconn, (char *)buffer, bufferlen);
|
||||||
|
xconn->client->sconn->num_requests++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only a 'normal' message type allowed now. */
|
||||||
|
if (msg_type != NBSSmessage) {
|
||||||
|
DBG_ERR("Invalid message type %d\n", msg_type);
|
||||||
|
exit_server_cleanly("Invalid message type for initial request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Could this be an SMB1 negprot bootstrap into SMB2 ? */
|
||||||
|
if (bufferlen < smb_size) {
|
||||||
|
exit_server_cleanly("Invalid initial SMB1 or SMB2 packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if defined(WITH_SMB1SERVER)
|
||||||
|
if (valid_smb_header(buffer)) {
|
||||||
|
/* Can *only* allow an SMB1 negprot here. */
|
||||||
|
uint8_t cmd = PULL_LE_U8(buffer, smb_com);
|
||||||
|
if (cmd != SMBnegprot) {
|
||||||
|
DBG_ERR("Incorrect SMB1 command 0x%hhx, "
|
||||||
|
"should be SMBnegprot (0x72)\n",
|
||||||
|
cmd);
|
||||||
|
exit_server_cleanly("Invalid initial SMB1 packet");
|
||||||
|
}
|
||||||
|
/* Minimal process_smb(). */
|
||||||
|
show_msg((char *)buffer);
|
||||||
|
construct_reply(xconn,
|
||||||
|
(char *)buffer,
|
||||||
|
bufferlen,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
NULL);
|
||||||
|
xconn->client->sconn->trans_num++;
|
||||||
|
xconn->client->sconn->num_requests++;
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (!smbd_is_smb2_header(buffer, bufferlen)) {
|
||||||
|
exit_server_cleanly("Invalid initial SMB2 packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here we know we're a valid SMB2 packet. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Point at the start of the SMB2 PDU.
|
||||||
|
* len is the length of the SMB2 PDU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status = smbd_smb2_process_negprot(xconn,
|
||||||
|
0,
|
||||||
|
(const uint8_t *)buffer+NBT_HDR_SIZE,
|
||||||
|
len);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
exit_server_cleanly("SMB2 negprot fail");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbd_server_connection_handler(struct tevent_context *ev,
|
||||||
|
struct tevent_fd *fde,
|
||||||
|
uint16_t flags,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct smbXsrv_connection *xconn =
|
||||||
|
talloc_get_type_abort(private_data,
|
||||||
|
struct smbXsrv_connection);
|
||||||
|
|
||||||
|
if (!NT_STATUS_IS_OK(xconn->transport.status)) {
|
||||||
|
/*
|
||||||
|
* we're not supposed to do any io
|
||||||
|
*/
|
||||||
|
TEVENT_FD_NOT_READABLE(xconn->transport.fde);
|
||||||
|
TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & TEVENT_FD_WRITE) {
|
||||||
|
smbd_server_connection_write_handler(xconn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flags & TEVENT_FD_READ) {
|
||||||
|
#if defined(WITH_SMB1SERVER)
|
||||||
|
if (lp_server_min_protocol() > PROTOCOL_NT1) {
|
||||||
|
#endif
|
||||||
|
smbd_smb2_server_connection_read_handler(xconn,
|
||||||
|
xconn->transport.sock);
|
||||||
|
#if defined(WITH_SMB1SERVER)
|
||||||
|
} else {
|
||||||
|
smbd_smb1_server_connection_read_handler(xconn,
|
||||||
|
xconn->transport.sock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct smbd_release_ip_state {
|
||||||
|
struct smbXsrv_connection *xconn;
|
||||||
|
struct tevent_immediate *im;
|
||||||
|
char addr[INET6_ADDRSTRLEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void smbd_release_ip_immediate(struct tevent_context *ctx,
|
||||||
|
struct tevent_immediate *im,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct smbd_release_ip_state *state =
|
||||||
|
talloc_get_type_abort(private_data,
|
||||||
|
struct smbd_release_ip_state);
|
||||||
|
struct smbXsrv_connection *xconn = state->xconn;
|
||||||
|
|
||||||
|
if (!NT_STATUS_EQUAL(xconn->transport.status, NT_STATUS_ADDRESS_CLOSED)) {
|
||||||
|
/*
|
||||||
|
* smbd_server_connection_terminate() already triggered ?
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
smbd_server_connection_terminate(xconn, "CTDB_SRVID_RELEASE_IP");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
received when we should release a specific IP
|
||||||
|
****************************************************************************/
|
||||||
|
static int release_ip(struct tevent_context *ev,
|
||||||
|
uint32_t src_vnn, uint32_t dst_vnn,
|
||||||
|
uint64_t dst_srvid,
|
||||||
|
const uint8_t *msg, size_t msglen,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct smbd_release_ip_state *state =
|
||||||
|
talloc_get_type_abort(private_data,
|
||||||
|
struct smbd_release_ip_state);
|
||||||
|
struct smbXsrv_connection *xconn = state->xconn;
|
||||||
|
const char *ip;
|
||||||
|
const char *addr = state->addr;
|
||||||
|
const char *p = addr;
|
||||||
|
|
||||||
|
if (msglen == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (msg[msglen-1] != '\0') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = (const char *)msg;
|
||||||
|
|
||||||
|
if (!NT_STATUS_IS_OK(xconn->transport.status)) {
|
||||||
|
/* avoid recursion */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp("::ffff:", addr, 7) == 0) {
|
||||||
|
p = addr + 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10, ("Got release IP message for %s, "
|
||||||
|
"our address is %s\n", ip, p));
|
||||||
|
|
||||||
|
if ((strcmp(p, ip) == 0) || ((p != addr) && strcmp(addr, ip) == 0)) {
|
||||||
|
DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
|
||||||
|
ip));
|
||||||
|
/*
|
||||||
|
* With SMB2 we should do a clean disconnect,
|
||||||
|
* the previous_session_id in the session setup
|
||||||
|
* will cleanup the old session, tcons and opens.
|
||||||
|
*
|
||||||
|
* A clean disconnect is needed in order to support
|
||||||
|
* durable handles.
|
||||||
|
*
|
||||||
|
* Note: typically this is never triggered
|
||||||
|
* as we got a TCP RST (triggered by ctdb event scripts)
|
||||||
|
* before we get CTDB_SRVID_RELEASE_IP.
|
||||||
|
*
|
||||||
|
* We used to call _exit(1) here, but as this was mostly never
|
||||||
|
* triggered and has implication on our process model,
|
||||||
|
* we can just use smbd_server_connection_terminate()
|
||||||
|
* (also for SMB1).
|
||||||
|
*
|
||||||
|
* We don't call smbd_server_connection_terminate() directly
|
||||||
|
* as we might be called from within ctdbd_migrate(),
|
||||||
|
* we need to defer our action to the next event loop
|
||||||
|
*/
|
||||||
|
tevent_schedule_immediate(state->im,
|
||||||
|
xconn->client->raw_ev_ctx,
|
||||||
|
smbd_release_ip_immediate,
|
||||||
|
state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure we don't get any io on the connection.
|
||||||
|
*/
|
||||||
|
xconn->transport.status = NT_STATUS_ADDRESS_CLOSED;
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match_cluster_movable_ip(uint32_t total_ip_count,
|
||||||
|
const struct sockaddr_storage *ip,
|
||||||
|
bool is_movable_ip,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
const struct sockaddr_storage *srv = private_data;
|
||||||
|
struct samba_sockaddr pub_ip = {
|
||||||
|
.u = {
|
||||||
|
.ss = *ip,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
struct samba_sockaddr srv_ip = {
|
||||||
|
.u = {
|
||||||
|
.ss = *srv,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (is_movable_ip && sockaddr_equal(&pub_ip.u.sa, &srv_ip.u.sa)) {
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
|
||||||
|
struct sockaddr_storage *srv,
|
||||||
|
struct sockaddr_storage *clnt)
|
||||||
|
{
|
||||||
|
struct smbd_release_ip_state *state;
|
||||||
|
struct ctdbd_connection *cconn;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cconn = messaging_ctdb_connection();
|
||||||
|
if (cconn == NULL) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = talloc_zero(xconn, struct smbd_release_ip_state);
|
||||||
|
if (state == NULL) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
state->xconn = xconn;
|
||||||
|
state->im = tevent_create_immediate(state);
|
||||||
|
if (state->im == NULL) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
if (print_sockaddr(state->addr, sizeof(state->addr), srv) == NULL) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xconn->client->server_multi_channel_enabled) {
|
||||||
|
ret = ctdbd_public_ip_foreach(cconn,
|
||||||
|
match_cluster_movable_ip,
|
||||||
|
srv);
|
||||||
|
if (ret == EADDRNOTAVAIL) {
|
||||||
|
xconn->has_cluster_movable_ip = true;
|
||||||
|
DBG_DEBUG("cluster movable IP on %s\n",
|
||||||
|
smbXsrv_connection_dbg(xconn));
|
||||||
|
} else if (ret != 0) {
|
||||||
|
DBG_ERR("failed to iterate cluster IPs: %s\n",
|
||||||
|
strerror(ret));
|
||||||
|
return NT_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
|
||||||
|
if (ret != 0) {
|
||||||
|
return map_nt_error_from_unix(ret);
|
||||||
|
}
|
||||||
|
return NT_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smbXsrv_connection_destructor(struct smbXsrv_connection *xconn)
|
||||||
|
{
|
||||||
|
DBG_DEBUG("xconn[%s]\n", smbXsrv_connection_dbg(xconn));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
|
||||||
|
NTTIME now, struct smbXsrv_connection **_xconn)
|
||||||
|
{
|
||||||
|
TALLOC_CTX *frame = talloc_stackframe();
|
||||||
|
struct smbXsrv_connection *xconn;
|
||||||
|
struct sockaddr_storage ss_srv;
|
||||||
|
void *sp_srv = (void *)&ss_srv;
|
||||||
|
struct sockaddr *sa_srv = (struct sockaddr *)sp_srv;
|
||||||
|
struct sockaddr_storage ss_clnt;
|
||||||
|
void *sp_clnt = (void *)&ss_clnt;
|
||||||
|
struct sockaddr *sa_clnt = (struct sockaddr *)sp_clnt;
|
||||||
|
socklen_t sa_socklen;
|
||||||
|
struct tsocket_address *local_address = NULL;
|
||||||
|
struct tsocket_address *remote_address = NULL;
|
||||||
|
const char *remaddr = NULL;
|
||||||
|
char *p;
|
||||||
|
const char *rhost = NULL;
|
||||||
|
int ret;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
*_xconn = NULL;
|
||||||
|
|
||||||
|
DO_PROFILE_INC(connect);
|
||||||
|
|
||||||
|
xconn = talloc_zero(client, struct smbXsrv_connection);
|
||||||
|
if (xconn == NULL) {
|
||||||
|
DEBUG(0,("talloc_zero(struct smbXsrv_connection)\n"));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
talloc_set_destructor(xconn, smbXsrv_connection_destructor);
|
||||||
|
talloc_steal(frame, xconn);
|
||||||
|
xconn->client = client;
|
||||||
|
xconn->connect_time = now;
|
||||||
|
if (client->next_channel_id != 0) {
|
||||||
|
xconn->channel_id = client->next_channel_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
xconn->transport.sock = sock_fd;
|
||||||
|
#if defined(WITH_SMB1SERVER)
|
||||||
|
smbd_echo_init(xconn);
|
||||||
|
#endif
|
||||||
|
xconn->protocol = PROTOCOL_NONE;
|
||||||
|
|
||||||
|
/* Ensure child is set to blocking mode */
|
||||||
|
set_blocking(sock_fd,True);
|
||||||
|
|
||||||
|
set_socket_options(sock_fd, "SO_KEEPALIVE");
|
||||||
|
set_socket_options(sock_fd, lp_socket_options());
|
||||||
|
|
||||||
|
sa_socklen = sizeof(ss_clnt);
|
||||||
|
ret = getpeername(sock_fd, sa_clnt, &sa_socklen);
|
||||||
|
if (ret != 0) {
|
||||||
|
int saved_errno = errno;
|
||||||
|
int level = (errno == ENOTCONN)?2:0;
|
||||||
|
DEBUG(level,("getpeername() failed - %s\n",
|
||||||
|
strerror(saved_errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return map_nt_error_from_unix_common(saved_errno);
|
||||||
|
}
|
||||||
|
ret = tsocket_address_bsd_from_sockaddr(xconn,
|
||||||
|
sa_clnt, sa_socklen,
|
||||||
|
&remote_address);
|
||||||
|
if (ret != 0) {
|
||||||
|
int saved_errno = errno;
|
||||||
|
DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
|
||||||
|
__location__, strerror(saved_errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return map_nt_error_from_unix_common(saved_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
sa_socklen = sizeof(ss_srv);
|
||||||
|
ret = getsockname(sock_fd, sa_srv, &sa_socklen);
|
||||||
|
if (ret != 0) {
|
||||||
|
int saved_errno = errno;
|
||||||
|
int level = (errno == ENOTCONN)?2:0;
|
||||||
|
DEBUG(level,("getsockname() failed - %s\n",
|
||||||
|
strerror(saved_errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return map_nt_error_from_unix_common(saved_errno);
|
||||||
|
}
|
||||||
|
ret = tsocket_address_bsd_from_sockaddr(xconn,
|
||||||
|
sa_srv, sa_socklen,
|
||||||
|
&local_address);
|
||||||
|
if (ret != 0) {
|
||||||
|
int saved_errno = errno;
|
||||||
|
DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
|
||||||
|
__location__, strerror(saved_errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return map_nt_error_from_unix_common(saved_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tsocket_address_is_inet(remote_address, "ip")) {
|
||||||
|
remaddr = tsocket_address_inet_addr_string(remote_address,
|
||||||
|
talloc_tos());
|
||||||
|
if (remaddr == NULL) {
|
||||||
|
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
|
||||||
|
__location__, strerror(errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaddr = "0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before the first packet, check the global hosts allow/ hosts deny
|
||||||
|
* parameters before doing any parsing of packets passed to us by the
|
||||||
|
* client. This prevents attacks on our parsing code from hosts not in
|
||||||
|
* the hosts allow list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = get_remote_hostname(remote_address,
|
||||||
|
&p, talloc_tos());
|
||||||
|
if (ret < 0) {
|
||||||
|
int saved_errno = errno;
|
||||||
|
DEBUG(0,("%s: get_remote_hostname failed - %s\n",
|
||||||
|
__location__, strerror(saved_errno)));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return map_nt_error_from_unix_common(saved_errno);
|
||||||
|
}
|
||||||
|
rhost = p;
|
||||||
|
if (strequal(rhost, "UNKNOWN")) {
|
||||||
|
rhost = remaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
xconn->local_address = local_address;
|
||||||
|
xconn->remote_address = remote_address;
|
||||||
|
xconn->remote_hostname = talloc_strdup(xconn, rhost);
|
||||||
|
if (xconn->remote_hostname == NULL) {
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srv_init_signing(xconn)) {
|
||||||
|
DEBUG(0, ("Failed to init smb_signing\n"));
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1),
|
||||||
|
xconn->remote_hostname,
|
||||||
|
remaddr)) {
|
||||||
|
DEBUG( 1, ("Connection denied from %s to %s\n",
|
||||||
|
tsocket_address_string(remote_address, talloc_tos()),
|
||||||
|
tsocket_address_string(local_address, talloc_tos())));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We return a valid xconn
|
||||||
|
* so that the caller can return an error message
|
||||||
|
* to the client
|
||||||
|
*/
|
||||||
|
DLIST_ADD_END(client->connections, xconn);
|
||||||
|
talloc_steal(client, xconn);
|
||||||
|
|
||||||
|
*_xconn = xconn;
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_NETWORK_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10, ("Connection allowed from %s to %s\n",
|
||||||
|
tsocket_address_string(remote_address, talloc_tos()),
|
||||||
|
tsocket_address_string(local_address, talloc_tos())));
|
||||||
|
|
||||||
|
if (lp_clustering()) {
|
||||||
|
/*
|
||||||
|
* We need to tell ctdb about our client's TCP
|
||||||
|
* connection, so that for failover ctdbd can send
|
||||||
|
* tickle acks, triggering a reconnection by the
|
||||||
|
* client.
|
||||||
|
*/
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = smbd_register_ips(xconn, &ss_srv, &ss_clnt);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
DEBUG(0, ("ctdbd_register_ips failed: %s\n",
|
||||||
|
nt_errstr(status)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = lp_max_xmit();
|
||||||
|
tmp = MAX(tmp, SMB_BUFFER_SIZE_MIN);
|
||||||
|
tmp = MIN(tmp, SMB_BUFFER_SIZE_MAX);
|
||||||
|
|
||||||
|
#if defined(WITH_SMB1SERVER)
|
||||||
|
xconn->smb1.negprot.max_recv = tmp;
|
||||||
|
|
||||||
|
xconn->smb1.sessions.done_sesssetup = false;
|
||||||
|
xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
xconn->transport.fde = tevent_add_fd(client->raw_ev_ctx,
|
||||||
|
xconn,
|
||||||
|
sock_fd,
|
||||||
|
TEVENT_FD_READ,
|
||||||
|
smbd_server_connection_handler,
|
||||||
|
xconn);
|
||||||
|
if (!xconn->transport.fde) {
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
tevent_fd_set_auto_close(xconn->transport.fde);
|
||||||
|
|
||||||
|
/* for now we only have one connection */
|
||||||
|
DLIST_ADD_END(client->connections, xconn);
|
||||||
|
talloc_steal(client, xconn);
|
||||||
|
|
||||||
|
*_xconn = xconn;
|
||||||
|
TALLOC_FREE(frame);
|
||||||
|
return NT_STATUS_OK;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user