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

smbd: Move smbd_process to smb2_process.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-21 08:05:15 -06:00 committed by Jeremy Allison
parent 2e0e49f41b
commit 43672e1558
3 changed files with 621 additions and 620 deletions

View File

@ -708,76 +708,6 @@ bool push_deferred_open_message_smb1(struct smb_request *req,
return push_queued_message(req, req->request_time, end_time, open_rec);
}
static void smbd_sig_term_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
exit_server_cleanly("termination signal");
}
static void smbd_setup_sig_term_handler(struct smbd_server_connection *sconn)
{
struct tevent_signal *se;
se = tevent_add_signal(sconn->ev_ctx,
sconn,
SIGTERM, 0,
smbd_sig_term_handler,
sconn);
if (!se) {
exit_server("failed to setup SIGTERM handler");
}
}
static void smbd_sig_hup_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
change_to_root_user();
DEBUG(1,("Reloading services after SIGHUP\n"));
reload_services(sconn, conn_snum_used, false);
}
static void smbd_setup_sig_hup_handler(struct smbd_server_connection *sconn)
{
struct tevent_signal *se;
se = tevent_add_signal(sconn->ev_ctx,
sconn,
SIGHUP, 0,
smbd_sig_hup_handler,
sconn);
if (!se) {
exit_server("failed to setup SIGHUP handler");
}
}
static void smbd_conf_updated(struct messaging_context *msg,
void *private_data,
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB *data)
{
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
DEBUG(10,("smbd_conf_updated: Got message saying smb.conf was "
"updated. Reloading.\n"));
change_to_root_user();
reload_services(sconn, conn_snum_used, false);
}
/*
* Only allow 5 outstanding trans requests. We're allocating memory, so
* prevent a DoS.
@ -2117,23 +2047,6 @@ bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
return true;
}
/****************************************************************************
Check if services need reloading.
****************************************************************************/
static void check_reload(struct smbd_server_connection *sconn, time_t t)
{
if (last_smb_conf_reload_time == 0) {
last_smb_conf_reload_time = t;
}
if (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK) {
reload_services(sconn, conn_snum_used, true);
last_smb_conf_reload_time = t;
}
}
static bool fd_is_readable(int fd)
{
int ret, revents;
@ -2244,36 +2157,10 @@ static void smbd_server_echo_handler(struct tevent_context *ev,
}
}
static void msg_kill_client_ip(struct messaging_context *msg_ctx,
void *private_data, uint32_t msg_type,
struct server_id server_id, DATA_BLOB *data)
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
const char *ip = (char *) data->data;
char *client_ip;
DBG_DEBUG("Got kill request for client IP %s\n", ip);
client_ip = tsocket_address_inet_addr_string(sconn->remote_address,
talloc_tos());
if (client_ip == NULL) {
return;
}
if (strequal(ip, client_ip)) {
DBG_WARNING("Got kill client message for %s - "
"exiting immediately\n", ip);
exit_server_cleanly("Forced disconnect for client");
}
TALLOC_FREE(client_ip);
}
/*
* Send keepalive packets to our client
*/
static bool keepalive_fn(const struct timeval *now, void *private_data)
bool keepalive_fn(const struct timeval *now, void *private_data)
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
@ -2309,50 +2196,6 @@ static bool keepalive_fn(const struct timeval *now, void *private_data)
return True;
}
/*
* Do the recurring check if we're idle
*/
static bool deadtime_fn(const struct timeval *now, void *private_data)
{
struct smbd_server_connection *sconn =
(struct smbd_server_connection *)private_data;
if ((conn_num_open(sconn) == 0)
|| (conn_idle_all(sconn, now->tv_sec))) {
DEBUG( 2, ( "Closing idle connection\n" ) );
messaging_send(sconn->msg_ctx,
messaging_server_id(sconn->msg_ctx),
MSG_SHUTDOWN, &data_blob_null);
return False;
}
return True;
}
/*
* Do the recurring log file and smb.conf reload checks.
*/
static bool housekeeping_fn(const struct timeval *now, void *private_data)
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
DEBUG(5, ("housekeeping\n"));
change_to_root_user();
/* check if we need to reload services */
check_reload(sconn, time_mono(NULL));
/*
* Force a log file check.
*/
force_check_log_size();
check_log_size();
return true;
}
/*
* Read an smb packet in the echo handler child, giving the parent
* smbd one second to react once the socket becomes readable.
@ -2903,464 +2746,6 @@ fail:
return false;
}
static bool uid_in_use(struct auth_session_info *session_info,
uid_t uid)
{
if (session_info->unix_token->uid == uid) {
return true;
}
return false;
}
static bool gid_in_use(struct auth_session_info *session_info,
gid_t gid)
{
uint32_t i;
struct security_unix_token *utok = NULL;
utok = session_info->unix_token;
if (utok->gid == gid) {
return true;
}
for(i = 0; i < utok->ngroups; i++) {
if (utok->groups[i] == gid) {
return true;
}
}
return false;
}
static bool sid_in_use(struct auth_session_info *session_info,
const struct dom_sid *psid)
{
struct security_token *tok = NULL;
tok = session_info->security_token;
if (tok == NULL) {
/*
* Not sure session_info->security_token can
* ever be NULL. This check might be not
* necessary.
*/
return false;
}
if (security_token_has_sid(tok, psid)) {
return true;
}
return false;
}
struct id_in_use_state {
const struct id_cache_ref *id;
bool match;
};
static int id_in_use_cb(struct smbXsrv_session *session,
void *private_data)
{
struct id_in_use_state *state = (struct id_in_use_state *)
private_data;
struct auth_session_info *session_info =
session->global->auth_session_info;
switch(state->id->type) {
case UID:
state->match = uid_in_use(session_info, state->id->id.uid);
break;
case GID:
state->match = gid_in_use(session_info, state->id->id.gid);
break;
case SID:
state->match = sid_in_use(session_info, &state->id->id.sid);
break;
default:
state->match = false;
break;
}
if (state->match) {
return -1;
}
return 0;
}
static bool id_in_use(struct smbd_server_connection *sconn,
const struct id_cache_ref *id)
{
struct id_in_use_state state;
NTSTATUS status;
state = (struct id_in_use_state) {
.id = id,
.match = false,
};
status = smbXsrv_session_local_traverse(sconn->client,
id_in_use_cb,
&state);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
return state.match;
}
static void smbd_id_cache_kill(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB* data)
{
const char *msg = (data && data->data)
? (const char *)data->data : "<NULL>";
struct id_cache_ref id;
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
if (!id_cache_ref_parse(msg, &id)) {
DEBUG(0, ("Invalid ?ID: %s\n", msg));
return;
}
if (id_in_use(sconn, &id)) {
exit_server_cleanly(msg);
}
id_cache_delete_from_cache(&id);
}
struct smbd_tevent_trace_state {
struct tevent_context *ev;
TALLOC_CTX *frame;
SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
};
static void smbd_tevent_trace_callback(enum tevent_trace_point point,
void *private_data)
{
struct smbd_tevent_trace_state *state =
(struct smbd_tevent_trace_state *)private_data;
switch (point) {
case TEVENT_TRACE_BEFORE_WAIT:
if (!smbprofile_dump_pending()) {
/*
* If there's no dump pending
* we don't want to schedule a new 1 sec timer.
*
* Instead we want to sleep as long as nothing happens.
*/
smbprofile_dump_setup(NULL);
}
SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
break;
case TEVENT_TRACE_AFTER_WAIT:
SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
if (!smbprofile_dump_pending()) {
/*
* We need to flush our state after sleeping
* (hopefully a long time).
*/
smbprofile_dump();
/*
* future profiling events should trigger timers
* on our main event context.
*/
smbprofile_dump_setup(state->ev);
}
break;
case TEVENT_TRACE_BEFORE_LOOP_ONCE:
TALLOC_FREE(state->frame);
state->frame = talloc_stackframe_pool(8192);
break;
case TEVENT_TRACE_AFTER_LOOP_ONCE:
TALLOC_FREE(state->frame);
break;
}
errno = 0;
}
/****************************************************************************
Process commands from the client
****************************************************************************/
void smbd_process(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
int sock_fd,
bool interactive)
{
struct smbd_tevent_trace_state trace_state = {
.ev = ev_ctx,
.frame = talloc_stackframe(),
};
const struct loadparm_substitution *lp_sub =
loadparm_s3_global_substitution();
struct smbXsrv_client *client = NULL;
struct smbd_server_connection *sconn = NULL;
struct smbXsrv_connection *xconn = NULL;
const char *locaddr = NULL;
const char *remaddr = NULL;
int ret;
NTSTATUS status;
struct timeval tv = timeval_current();
NTTIME now = timeval_to_nttime(&tv);
char *chroot_dir = NULL;
int rc;
status = smbXsrv_client_create(ev_ctx, ev_ctx, msg_ctx, now, &client);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("smbXsrv_client_create(): %s\n", nt_errstr(status));
exit_server_cleanly("talloc_zero(struct smbXsrv_client).\n");
}
/*
* TODO: remove this...:-)
*/
global_smbXsrv_client = client;
sconn = talloc_zero(client, struct smbd_server_connection);
if (sconn == NULL) {
exit_server("failed to create smbd_server_connection");
}
client->sconn = sconn;
sconn->client = client;
sconn->ev_ctx = ev_ctx;
sconn->msg_ctx = msg_ctx;
ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
&sconn->pool);
if (ret != 0) {
exit_server("pthreadpool_tevent_init() failed.");
}
#if defined(WITH_SMB1SERVER)
if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
#endif
/*
* We're not making the decision here,
* we're just allowing the client
* to decide between SMB1 and SMB2
* with the first negprot
* packet.
*/
sconn->using_smb2 = true;
#if defined(WITH_SMB1SERVER)
}
#endif
if (!interactive) {
smbd_setup_sig_term_handler(sconn);
smbd_setup_sig_hup_handler(sconn);
}
status = smbd_add_connection(client, sock_fd, now, &xconn);
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
/*
* send a negative session response "not listening on calling
* name"
*/
unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
(void)srv_send_smb(xconn,(char *)buf, false,
0, false, NULL);
exit_server_cleanly("connection denied");
} else if (!NT_STATUS_IS_OK(status)) {
exit_server_cleanly(nt_errstr(status));
}
sconn->local_address =
tsocket_address_copy(xconn->local_address, sconn);
if (sconn->local_address == NULL) {
exit_server_cleanly("tsocket_address_copy() failed");
}
sconn->remote_address =
tsocket_address_copy(xconn->remote_address, sconn);
if (sconn->remote_address == NULL) {
exit_server_cleanly("tsocket_address_copy() failed");
}
sconn->remote_hostname =
talloc_strdup(sconn, xconn->remote_hostname);
if (sconn->remote_hostname == NULL) {
exit_server_cleanly("tsocket_strdup() failed");
}
client->global->local_address =
tsocket_address_string(sconn->local_address,
client->global);
if (client->global->local_address == NULL) {
exit_server_cleanly("tsocket_address_string() failed");
}
client->global->remote_address =
tsocket_address_string(sconn->remote_address,
client->global);
if (client->global->remote_address == NULL) {
exit_server_cleanly("tsocket_address_string() failed");
}
client->global->remote_name =
talloc_strdup(client->global, sconn->remote_hostname);
if (client->global->remote_name == NULL) {
exit_server_cleanly("tsocket_strdup() failed");
}
if (tsocket_address_is_inet(sconn->local_address, "ip")) {
locaddr = tsocket_address_inet_addr_string(
sconn->local_address,
talloc_tos());
if (locaddr == NULL) {
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
__location__, strerror(errno)));
exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
}
} else {
locaddr = "0.0.0.0";
}
if (tsocket_address_is_inet(sconn->remote_address, "ip")) {
remaddr = tsocket_address_inet_addr_string(
sconn->remote_address,
talloc_tos());
if (remaddr == NULL) {
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
__location__, strerror(errno)));
exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
}
} else {
remaddr = "0.0.0.0";
}
/* this is needed so that we get decent entries
in smbstatus for port 445 connects */
set_remote_machine_name(remaddr, false);
reload_services(sconn, conn_snum_used, true);
sub_set_socket_ids(remaddr,
sconn->remote_hostname,
locaddr);
if (lp_preload_modules()) {
smb_load_all_modules_absoute_path(lp_preload_modules());
}
smb_perfcount_init();
if (!init_account_policy()) {
exit_server("Could not open account policy tdb.\n");
}
chroot_dir = lp_root_directory(talloc_tos(), lp_sub);
if (chroot_dir[0] != '\0') {
rc = chdir(chroot_dir);
if (rc != 0) {
DBG_ERR("Failed to chdir to %s\n", chroot_dir);
exit_server("Failed to chdir()");
}
rc = chroot(chroot_dir);
if (rc != 0) {
DBG_ERR("Failed to change root to %s\n", chroot_dir);
exit_server("Failed to chroot()");
}
DBG_WARNING("Changed root to %s\n", chroot_dir);
TALLOC_FREE(chroot_dir);
}
if (!file_init(sconn)) {
exit_server("file_init() failed");
}
/* Setup oplocks */
if (!init_oplocks(sconn))
exit_server("Failed to init oplocks");
/* register our message handlers */
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_FORCE_TDIS, msg_force_tdis);
messaging_register(
sconn->msg_ctx,
sconn,
MSG_SMB_FORCE_TDIS_DENIED,
msg_force_tdis_denied);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_CLOSE_FILE, msg_close_file);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_FILE_RENAME, msg_file_was_renamed);
id_cache_register_msgs(sconn->msg_ctx);
messaging_deregister(sconn->msg_ctx, ID_CACHE_KILL, NULL);
messaging_register(sconn->msg_ctx, sconn,
ID_CACHE_KILL, smbd_id_cache_kill);
messaging_deregister(sconn->msg_ctx,
MSG_SMB_CONF_UPDATED, sconn->ev_ctx);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_CONF_UPDATED, smbd_conf_updated);
messaging_deregister(sconn->msg_ctx, MSG_SMB_KILL_CLIENT_IP,
NULL);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_KILL_CLIENT_IP,
msg_kill_client_ip);
messaging_deregister(sconn->msg_ctx, MSG_SMB_TELL_NUM_CHILDREN, NULL);
/*
* Use the default MSG_DEBUG handler to avoid rebroadcasting
* MSGs to all child processes
*/
messaging_deregister(sconn->msg_ctx,
MSG_DEBUG, NULL);
messaging_register(sconn->msg_ctx, NULL,
MSG_DEBUG, debug_message);
#if defined(WITH_SMB1SERVER)
if ((lp_keepalive() != 0)
&& !(event_add_idle(ev_ctx, NULL,
timeval_set(lp_keepalive(), 0),
"keepalive", keepalive_fn,
sconn))) {
DEBUG(0, ("Could not add keepalive event\n"));
exit(1);
}
#endif
if (!(event_add_idle(ev_ctx, NULL,
timeval_set(IDLE_CLOSED_TIMEOUT, 0),
"deadtime", deadtime_fn, sconn))) {
DEBUG(0, ("Could not add deadtime event\n"));
exit(1);
}
if (!(event_add_idle(ev_ctx, NULL,
timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
"housekeeping", housekeeping_fn, sconn))) {
DEBUG(0, ("Could not add housekeeping event\n"));
exit(1);
}
smbprofile_dump_setup(ev_ctx);
if (!init_dptrs(sconn)) {
exit_server("init_dptrs() failed");
}
TALLOC_FREE(trace_state.frame);
tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback,
&trace_state);
ret = tevent_loop_wait(ev_ctx);
if (ret != 0) {
DEBUG(1, ("tevent_loop_wait failed: %d, %s,"
" exiting\n", ret, strerror(errno)));
}
TALLOC_FREE(trace_state.frame);
exit_server_cleanly(NULL);
}
bool req_is_in_chain(const struct smb_request *req)
{
if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) {

View File

@ -870,10 +870,6 @@ bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
bool encrypted, uint32_t seqnum,
struct smb_request ***reqs, unsigned *num_reqs);
bool req_is_in_chain(const struct smb_request *req);
void smbd_process(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
int sock_fd,
bool interactive);
bool fork_echo_handler(struct smbXsrv_connection *xconn);
NTSTATUS smb1_receive_talloc(TALLOC_CTX *mem_ctx,
struct smbXsrv_connection *xconn,
@ -899,6 +895,7 @@ void construct_reply(struct smbXsrv_connection *xconn,
struct smb_perfcount_data *deferred_pcd);
void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
int fd);
bool keepalive_fn(const struct timeval *now, void *private_data);
/* The following definitions come from smbd/smb2_process.c */
@ -941,6 +938,10 @@ void process_smb(struct smbXsrv_connection *xconn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
uint32_t seqnum, bool encrypted,
struct smb_perfcount_data *deferred_pcd);
void smbd_process(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
int sock_fd,
bool interactive);
/* The following definitions come from smbd/quotas.c */

View File

@ -1284,3 +1284,618 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
TALLOC_FREE(frame);
return NT_STATUS_OK;
}
static bool uid_in_use(struct auth_session_info *session_info,
uid_t uid)
{
if (session_info->unix_token->uid == uid) {
return true;
}
return false;
}
static bool gid_in_use(struct auth_session_info *session_info,
gid_t gid)
{
uint32_t i;
struct security_unix_token *utok = NULL;
utok = session_info->unix_token;
if (utok->gid == gid) {
return true;
}
for(i = 0; i < utok->ngroups; i++) {
if (utok->groups[i] == gid) {
return true;
}
}
return false;
}
static bool sid_in_use(struct auth_session_info *session_info,
const struct dom_sid *psid)
{
struct security_token *tok = NULL;
tok = session_info->security_token;
if (tok == NULL) {
/*
* Not sure session_info->security_token can
* ever be NULL. This check might be not
* necessary.
*/
return false;
}
if (security_token_has_sid(tok, psid)) {
return true;
}
return false;
}
struct id_in_use_state {
const struct id_cache_ref *id;
bool match;
};
static int id_in_use_cb(struct smbXsrv_session *session,
void *private_data)
{
struct id_in_use_state *state = (struct id_in_use_state *)
private_data;
struct auth_session_info *session_info =
session->global->auth_session_info;
switch(state->id->type) {
case UID:
state->match = uid_in_use(session_info, state->id->id.uid);
break;
case GID:
state->match = gid_in_use(session_info, state->id->id.gid);
break;
case SID:
state->match = sid_in_use(session_info, &state->id->id.sid);
break;
default:
state->match = false;
break;
}
if (state->match) {
return -1;
}
return 0;
}
static bool id_in_use(struct smbd_server_connection *sconn,
const struct id_cache_ref *id)
{
struct id_in_use_state state;
NTSTATUS status;
state = (struct id_in_use_state) {
.id = id,
.match = false,
};
status = smbXsrv_session_local_traverse(sconn->client,
id_in_use_cb,
&state);
if (!NT_STATUS_IS_OK(status)) {
return false;
}
return state.match;
}
/****************************************************************************
Check if services need reloading.
****************************************************************************/
static void check_reload(struct smbd_server_connection *sconn, time_t t)
{
if (last_smb_conf_reload_time == 0) {
last_smb_conf_reload_time = t;
}
if (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK) {
reload_services(sconn, conn_snum_used, true);
last_smb_conf_reload_time = t;
}
}
static void msg_kill_client_ip(struct messaging_context *msg_ctx,
void *private_data, uint32_t msg_type,
struct server_id server_id, DATA_BLOB *data)
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
const char *ip = (char *) data->data;
char *client_ip;
DBG_DEBUG("Got kill request for client IP %s\n", ip);
client_ip = tsocket_address_inet_addr_string(sconn->remote_address,
talloc_tos());
if (client_ip == NULL) {
return;
}
if (strequal(ip, client_ip)) {
DBG_WARNING("Got kill client message for %s - "
"exiting immediately\n", ip);
exit_server_cleanly("Forced disconnect for client");
}
TALLOC_FREE(client_ip);
}
/*
* Do the recurring check if we're idle
*/
static bool deadtime_fn(const struct timeval *now, void *private_data)
{
struct smbd_server_connection *sconn =
(struct smbd_server_connection *)private_data;
if ((conn_num_open(sconn) == 0)
|| (conn_idle_all(sconn, now->tv_sec))) {
DEBUG( 2, ( "Closing idle connection\n" ) );
messaging_send(sconn->msg_ctx,
messaging_server_id(sconn->msg_ctx),
MSG_SHUTDOWN, &data_blob_null);
return False;
}
return True;
}
/*
* Do the recurring log file and smb.conf reload checks.
*/
static bool housekeeping_fn(const struct timeval *now, void *private_data)
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
DEBUG(5, ("housekeeping\n"));
change_to_root_user();
/* check if we need to reload services */
check_reload(sconn, time_mono(NULL));
/*
* Force a log file check.
*/
force_check_log_size();
check_log_size();
return true;
}
static void smbd_sig_term_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
exit_server_cleanly("termination signal");
}
static void smbd_setup_sig_term_handler(struct smbd_server_connection *sconn)
{
struct tevent_signal *se;
se = tevent_add_signal(sconn->ev_ctx,
sconn,
SIGTERM, 0,
smbd_sig_term_handler,
sconn);
if (!se) {
exit_server("failed to setup SIGTERM handler");
}
}
static void smbd_sig_hup_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
change_to_root_user();
DEBUG(1,("Reloading services after SIGHUP\n"));
reload_services(sconn, conn_snum_used, false);
}
static void smbd_setup_sig_hup_handler(struct smbd_server_connection *sconn)
{
struct tevent_signal *se;
se = tevent_add_signal(sconn->ev_ctx,
sconn,
SIGHUP, 0,
smbd_sig_hup_handler,
sconn);
if (!se) {
exit_server("failed to setup SIGHUP handler");
}
}
static void smbd_conf_updated(struct messaging_context *msg,
void *private_data,
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB *data)
{
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
DEBUG(10,("smbd_conf_updated: Got message saying smb.conf was "
"updated. Reloading.\n"));
change_to_root_user();
reload_services(sconn, conn_snum_used, false);
}
static void smbd_id_cache_kill(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB* data)
{
const char *msg = (data && data->data)
? (const char *)data->data : "<NULL>";
struct id_cache_ref id;
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
if (!id_cache_ref_parse(msg, &id)) {
DEBUG(0, ("Invalid ?ID: %s\n", msg));
return;
}
if (id_in_use(sconn, &id)) {
exit_server_cleanly(msg);
}
id_cache_delete_from_cache(&id);
}
struct smbd_tevent_trace_state {
struct tevent_context *ev;
TALLOC_CTX *frame;
SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
};
static void smbd_tevent_trace_callback(enum tevent_trace_point point,
void *private_data)
{
struct smbd_tevent_trace_state *state =
(struct smbd_tevent_trace_state *)private_data;
switch (point) {
case TEVENT_TRACE_BEFORE_WAIT:
if (!smbprofile_dump_pending()) {
/*
* If there's no dump pending
* we don't want to schedule a new 1 sec timer.
*
* Instead we want to sleep as long as nothing happens.
*/
smbprofile_dump_setup(NULL);
}
SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
break;
case TEVENT_TRACE_AFTER_WAIT:
SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
if (!smbprofile_dump_pending()) {
/*
* We need to flush our state after sleeping
* (hopefully a long time).
*/
smbprofile_dump();
/*
* future profiling events should trigger timers
* on our main event context.
*/
smbprofile_dump_setup(state->ev);
}
break;
case TEVENT_TRACE_BEFORE_LOOP_ONCE:
TALLOC_FREE(state->frame);
state->frame = talloc_stackframe_pool(8192);
break;
case TEVENT_TRACE_AFTER_LOOP_ONCE:
TALLOC_FREE(state->frame);
break;
}
errno = 0;
}
/****************************************************************************
Process commands from the client
****************************************************************************/
void smbd_process(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
int sock_fd,
bool interactive)
{
struct smbd_tevent_trace_state trace_state = {
.ev = ev_ctx,
.frame = talloc_stackframe(),
};
const struct loadparm_substitution *lp_sub =
loadparm_s3_global_substitution();
struct smbXsrv_client *client = NULL;
struct smbd_server_connection *sconn = NULL;
struct smbXsrv_connection *xconn = NULL;
const char *locaddr = NULL;
const char *remaddr = NULL;
int ret;
NTSTATUS status;
struct timeval tv = timeval_current();
NTTIME now = timeval_to_nttime(&tv);
char *chroot_dir = NULL;
int rc;
status = smbXsrv_client_create(ev_ctx, ev_ctx, msg_ctx, now, &client);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("smbXsrv_client_create(): %s\n", nt_errstr(status));
exit_server_cleanly("talloc_zero(struct smbXsrv_client).\n");
}
/*
* TODO: remove this...:-)
*/
global_smbXsrv_client = client;
sconn = talloc_zero(client, struct smbd_server_connection);
if (sconn == NULL) {
exit_server("failed to create smbd_server_connection");
}
client->sconn = sconn;
sconn->client = client;
sconn->ev_ctx = ev_ctx;
sconn->msg_ctx = msg_ctx;
ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
&sconn->pool);
if (ret != 0) {
exit_server("pthreadpool_tevent_init() failed.");
}
#if defined(WITH_SMB1SERVER)
if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
#endif
/*
* We're not making the decision here,
* we're just allowing the client
* to decide between SMB1 and SMB2
* with the first negprot
* packet.
*/
sconn->using_smb2 = true;
#if defined(WITH_SMB1SERVER)
}
#endif
if (!interactive) {
smbd_setup_sig_term_handler(sconn);
smbd_setup_sig_hup_handler(sconn);
}
status = smbd_add_connection(client, sock_fd, now, &xconn);
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
/*
* send a negative session response "not listening on calling
* name"
*/
unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
(void)srv_send_smb(xconn,(char *)buf, false,
0, false, NULL);
exit_server_cleanly("connection denied");
} else if (!NT_STATUS_IS_OK(status)) {
exit_server_cleanly(nt_errstr(status));
}
sconn->local_address =
tsocket_address_copy(xconn->local_address, sconn);
if (sconn->local_address == NULL) {
exit_server_cleanly("tsocket_address_copy() failed");
}
sconn->remote_address =
tsocket_address_copy(xconn->remote_address, sconn);
if (sconn->remote_address == NULL) {
exit_server_cleanly("tsocket_address_copy() failed");
}
sconn->remote_hostname =
talloc_strdup(sconn, xconn->remote_hostname);
if (sconn->remote_hostname == NULL) {
exit_server_cleanly("tsocket_strdup() failed");
}
client->global->local_address =
tsocket_address_string(sconn->local_address,
client->global);
if (client->global->local_address == NULL) {
exit_server_cleanly("tsocket_address_string() failed");
}
client->global->remote_address =
tsocket_address_string(sconn->remote_address,
client->global);
if (client->global->remote_address == NULL) {
exit_server_cleanly("tsocket_address_string() failed");
}
client->global->remote_name =
talloc_strdup(client->global, sconn->remote_hostname);
if (client->global->remote_name == NULL) {
exit_server_cleanly("tsocket_strdup() failed");
}
if (tsocket_address_is_inet(sconn->local_address, "ip")) {
locaddr = tsocket_address_inet_addr_string(
sconn->local_address,
talloc_tos());
if (locaddr == NULL) {
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
__location__, strerror(errno)));
exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
}
} else {
locaddr = "0.0.0.0";
}
if (tsocket_address_is_inet(sconn->remote_address, "ip")) {
remaddr = tsocket_address_inet_addr_string(
sconn->remote_address,
talloc_tos());
if (remaddr == NULL) {
DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
__location__, strerror(errno)));
exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
}
} else {
remaddr = "0.0.0.0";
}
/* this is needed so that we get decent entries
in smbstatus for port 445 connects */
set_remote_machine_name(remaddr, false);
reload_services(sconn, conn_snum_used, true);
sub_set_socket_ids(remaddr,
sconn->remote_hostname,
locaddr);
if (lp_preload_modules()) {
smb_load_all_modules_absoute_path(lp_preload_modules());
}
smb_perfcount_init();
if (!init_account_policy()) {
exit_server("Could not open account policy tdb.\n");
}
chroot_dir = lp_root_directory(talloc_tos(), lp_sub);
if (chroot_dir[0] != '\0') {
rc = chdir(chroot_dir);
if (rc != 0) {
DBG_ERR("Failed to chdir to %s\n", chroot_dir);
exit_server("Failed to chdir()");
}
rc = chroot(chroot_dir);
if (rc != 0) {
DBG_ERR("Failed to change root to %s\n", chroot_dir);
exit_server("Failed to chroot()");
}
DBG_WARNING("Changed root to %s\n", chroot_dir);
TALLOC_FREE(chroot_dir);
}
if (!file_init(sconn)) {
exit_server("file_init() failed");
}
/* Setup oplocks */
if (!init_oplocks(sconn))
exit_server("Failed to init oplocks");
/* register our message handlers */
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_FORCE_TDIS, msg_force_tdis);
messaging_register(
sconn->msg_ctx,
sconn,
MSG_SMB_FORCE_TDIS_DENIED,
msg_force_tdis_denied);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_CLOSE_FILE, msg_close_file);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_FILE_RENAME, msg_file_was_renamed);
id_cache_register_msgs(sconn->msg_ctx);
messaging_deregister(sconn->msg_ctx, ID_CACHE_KILL, NULL);
messaging_register(sconn->msg_ctx, sconn,
ID_CACHE_KILL, smbd_id_cache_kill);
messaging_deregister(sconn->msg_ctx,
MSG_SMB_CONF_UPDATED, sconn->ev_ctx);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_CONF_UPDATED, smbd_conf_updated);
messaging_deregister(sconn->msg_ctx, MSG_SMB_KILL_CLIENT_IP,
NULL);
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_KILL_CLIENT_IP,
msg_kill_client_ip);
messaging_deregister(sconn->msg_ctx, MSG_SMB_TELL_NUM_CHILDREN, NULL);
/*
* Use the default MSG_DEBUG handler to avoid rebroadcasting
* MSGs to all child processes
*/
messaging_deregister(sconn->msg_ctx,
MSG_DEBUG, NULL);
messaging_register(sconn->msg_ctx, NULL,
MSG_DEBUG, debug_message);
#if defined(WITH_SMB1SERVER)
if ((lp_keepalive() != 0)
&& !(event_add_idle(ev_ctx, NULL,
timeval_set(lp_keepalive(), 0),
"keepalive", keepalive_fn,
sconn))) {
DEBUG(0, ("Could not add keepalive event\n"));
exit(1);
}
#endif
if (!(event_add_idle(ev_ctx, NULL,
timeval_set(IDLE_CLOSED_TIMEOUT, 0),
"deadtime", deadtime_fn, sconn))) {
DEBUG(0, ("Could not add deadtime event\n"));
exit(1);
}
if (!(event_add_idle(ev_ctx, NULL,
timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
"housekeeping", housekeeping_fn, sconn))) {
DEBUG(0, ("Could not add housekeeping event\n"));
exit(1);
}
smbprofile_dump_setup(ev_ctx);
if (!init_dptrs(sconn)) {
exit_server("init_dptrs() failed");
}
TALLOC_FREE(trace_state.frame);
tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback,
&trace_state);
ret = tevent_loop_wait(ev_ctx);
if (ret != 0) {
DEBUG(1, ("tevent_loop_wait failed: %d, %s,"
" exiting\n", ret, strerror(errno)));
}
TALLOC_FREE(trace_state.frame);
exit_server_cleanly(NULL);
}