mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +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:
parent
2e0e49f41b
commit
43672e1558
@ -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);
|
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
|
* Only allow 5 outstanding trans requests. We're allocating memory, so
|
||||||
* prevent a DoS.
|
* prevent a DoS.
|
||||||
@ -2117,23 +2047,6 @@ bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
|
|||||||
return true;
|
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)
|
static bool fd_is_readable(int fd)
|
||||||
{
|
{
|
||||||
int ret, revents;
|
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
|
* 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(
|
struct smbd_server_connection *sconn = talloc_get_type_abort(
|
||||||
private_data, struct smbd_server_connection);
|
private_data, struct smbd_server_connection);
|
||||||
@ -2309,50 +2196,6 @@ static bool keepalive_fn(const struct timeval *now, void *private_data)
|
|||||||
return True;
|
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
|
* Read an smb packet in the echo handler child, giving the parent
|
||||||
* smbd one second to react once the socket becomes readable.
|
* smbd one second to react once the socket becomes readable.
|
||||||
@ -2903,464 +2746,6 @@ fail:
|
|||||||
return false;
|
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)
|
bool req_is_in_chain(const struct smb_request *req)
|
||||||
{
|
{
|
||||||
if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) {
|
if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) {
|
||||||
|
@ -870,10 +870,6 @@ bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
|
|||||||
bool encrypted, uint32_t seqnum,
|
bool encrypted, uint32_t seqnum,
|
||||||
struct smb_request ***reqs, unsigned *num_reqs);
|
struct smb_request ***reqs, unsigned *num_reqs);
|
||||||
bool req_is_in_chain(const struct smb_request *req);
|
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);
|
bool fork_echo_handler(struct smbXsrv_connection *xconn);
|
||||||
NTSTATUS smb1_receive_talloc(TALLOC_CTX *mem_ctx,
|
NTSTATUS smb1_receive_talloc(TALLOC_CTX *mem_ctx,
|
||||||
struct smbXsrv_connection *xconn,
|
struct smbXsrv_connection *xconn,
|
||||||
@ -899,6 +895,7 @@ void construct_reply(struct smbXsrv_connection *xconn,
|
|||||||
struct smb_perfcount_data *deferred_pcd);
|
struct smb_perfcount_data *deferred_pcd);
|
||||||
void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
|
void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
|
||||||
int fd);
|
int fd);
|
||||||
|
bool keepalive_fn(const struct timeval *now, void *private_data);
|
||||||
|
|
||||||
/* The following definitions come from smbd/smb2_process.c */
|
/* 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,
|
uint8_t *inbuf, size_t nread, 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);
|
||||||
|
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 */
|
/* The following definitions come from smbd/quotas.c */
|
||||||
|
|
||||||
|
@ -1284,3 +1284,618 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
|
|||||||
TALLOC_FREE(frame);
|
TALLOC_FREE(frame);
|
||||||
return NT_STATUS_OK;
|
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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user