/* this is the context for a SMB socket associated with the socket itself */
struct smbcli_socket {
- /* when the reference count reaches zero then the socket is destroyed */
- int reference_count;
-
struct in_addr dest_ip;
/* dest hostname (which may or may not be a DNS name) */
char *hostname;
/* this is the context for the client transport layer */
struct smbcli_transport {
- /* when the reference count reaches zero then the transport is destroyed */
- int reference_count;
-
/* socket level info */
struct smbcli_socket *socket;
/* this is the context for the session layer */
struct smbcli_session {
- /* when the reference count reaches zero then the session is destroyed */
- int reference_count;
-
/* transport layer info */
struct smbcli_transport *transport;
smbcli_tree context: internal state for a tree connection.
*/
struct smbcli_tree {
- /* when the reference count reaches zero then the tree is destroyed */
- int reference_count;
-
/* session layer info */
struct smbcli_session *session;
if (!sock) return False;
if (!smbcli_sock_connect_byname(sock, server, 0)) {
- smbcli_sock_close(sock);
+ talloc_free(sock);
return False;
}
cli->transport = smbcli_transport_init(sock);
if (!cli->transport) {
- smbcli_sock_close(sock);
+ talloc_free(sock);
return False;
}
cli->tree = smbcli_tree_init(cli->session);
if (!cli->tree) return NT_STATUS_UNSUCCESSFUL;
- cli->tree->reference_count++;
-
mem_ctx = talloc_init("tcon");
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
(*ret_cli)->tree = tree;
(*ret_cli)->session = tree->session;
(*ret_cli)->transport = tree->session->transport;
- tree->reference_count++;
done:
talloc_free(mem_ctx);
void smbcli_shutdown(struct smbcli_state *cli)
{
if (!cli) return;
- if (cli->tree) {
- cli->tree->reference_count++;
- smbcli_tree_close(cli->tree);
- }
+ talloc_free(cli->tree);
talloc_free(cli);
}
if (!req) return NULL; \
} while (0)
+
+/*
+ destroy a smbcli_session
+*/
+static int session_destroy(void *ptr)
+{
+ struct smbcli_session *session = ptr;
+ talloc_free(session->transport);
+ return 0;
+}
+
/****************************************************************************
Initialize the session context
****************************************************************************/
session->transport = transport;
session->pid = (uint16_t)getpid();
session->vuid = UID_FIELD_INVALID;
- session->transport->reference_count++;
- return session;
-}
+ talloc_set_destructor(session, session_destroy);
-/****************************************************************************
-reduce reference_count and destroy is <= 0
-****************************************************************************/
-void smbcli_session_close(struct smbcli_session *session)
-{
- session->reference_count--;
- if (session->reference_count <= 0) {
- smbcli_transport_close(session->transport);
- }
+ return session;
}
/****************************************************************************
/****************************************************************************
- Send a SMBexit
-****************************************************************************/
-NTSTATUS smb_raw_exit(struct smbcli_session *session)
+ Send a exit (async send)
+*****************************************************************************/
+struct smbcli_request *smb_raw_exit_send(struct smbcli_session *session)
{
struct smbcli_request *req;
- req = smbcli_request_setup_session(session, SMBexit, 0, 0);
+ SETUP_REQUEST_SESSION(SMBexit, 0, 0);
- if (smbcli_request_send(req)) {
- smbcli_request_receive(req);
+ if (!smbcli_request_send(req)) {
+ smbcli_request_destroy(req);
+ return NULL;
}
- return smbcli_request_destroy(req);
+
+ return req;
+}
+
+/****************************************************************************
+ Send a exit (sync interface)
+*****************************************************************************/
+NTSTATUS smb_raw_exit(struct smbcli_session *session)
+{
+ struct smbcli_request *req = smb_raw_exit_send(session);
+ return smbcli_request_simple_recv(req);
}
#include "includes.h"
+/*
+ destroy a socket
+ */
+static int sock_destructor(void *ptr)
+{
+ struct smbcli_socket *sock = ptr;
+ if (sock->fd != -1) {
+ close(sock->fd);
+ sock->fd = -1;
+ }
+ return 0;
+}
/*
create a smbcli_socket context
ZERO_STRUCTP(sock);
sock->fd = -1;
sock->port = 0;
+
/* 20 second default timeout */
sock->timeout = 20000;
-
sock->hostname = NULL;
+ talloc_set_destructor(sock, sock_destructor);
+
return sock;
}
}
}
-/****************************************************************************
- reduce socket reference count - if it becomes zero then close
-****************************************************************************/
-void smbcli_sock_close(struct smbcli_socket *sock)
-{
- sock->reference_count--;
- if (sock->reference_count <= 0) {
- smbcli_sock_dead(sock);
- talloc_free(sock);
- }
-}
-
/****************************************************************************
Set socket options on a open connection.
****************************************************************************/
}
}
+/*
+ destroy a transport
+ */
+static int transport_destructor(void *ptr)
+{
+ struct smbcli_transport *transport = ptr;
+
+ smbcli_transport_dead(transport);
+ event_remove_fd(transport->event.ctx, transport->event.fde);
+ event_remove_timed(transport->event.ctx, transport->event.te);
+ event_context_destroy(transport->event.ctx);
+ talloc_free(transport->socket);
+ return 0;
+}
+
/*
create a transport structure based on an established socket
*/
smbcli_init_signing(transport);
- transport->socket->reference_count++;
-
ZERO_STRUCT(transport->called);
fde.fd = sock->fd;
transport->event.fde = event_add_fd(transport->event.ctx, &fde);
- return transport;
-}
+ talloc_set_destructor(transport, transport_destructor);
-/*
- decrease reference count on a transport, and destroy if it becomes
- zero
-*/
-void smbcli_transport_close(struct smbcli_transport *transport)
-{
- transport->reference_count--;
- if (transport->reference_count <= 0) {
- event_remove_fd(transport->event.ctx, transport->event.fde);
- event_remove_timed(transport->event.ctx, transport->event.te);
- event_context_destroy(transport->event.ctx);
- smbcli_sock_close(transport->socket);
- }
+ return transport;
}
/*
if (!req) return NULL; \
} while (0)
+/*
+ destroy a smbcli_tree
+*/
+static int tree_destructor(void *ptr)
+{
+ struct smbcli_tree *tree = ptr;
+ talloc_free(tree->session);
+ return 0;
+}
/****************************************************************************
Initialize the tree context
ZERO_STRUCTP(tree);
tree->session = session;
- tree->session->reference_count++;
+ talloc_set_destructor(tree, tree_destructor);
return tree;
}
-/****************************************************************************
-reduce reference count on a tree and destroy if <= 0
-****************************************************************************/
-void smbcli_tree_close(struct smbcli_tree *tree)
-{
- if (!tree) return;
- tree->reference_count--;
- if (tree->reference_count <= 0) {
- smbcli_session_close(tree->session);
- }
-}
-
-
/****************************************************************************
Send a tconX (async send)
****************************************************************************/
transport = smbcli_transport_init(sock);
if (!transport) {
- smbcli_sock_close(sock);
+ talloc_free(sock);
return NT_STATUS_NO_MEMORY;
}
choose_called_name(&called, dest_host, 0x20);
if (!smbcli_transport_connect(transport, &calling, &called)) {
- smbcli_transport_close(transport);
+ talloc_free(transport);
return NT_STATUS_UNSUCCESSFUL;
}
/* negotiate protocol options with the server */
status = smb_raw_negotiate(transport);
if (!NT_STATUS_IS_OK(status)) {
- smbcli_transport_close(transport);
+ talloc_free(transport);
return status;
}
session = smbcli_session_init(transport);
if (!session) {
- smbcli_transport_close(transport);
+ talloc_free(transport);
return NT_STATUS_NO_MEMORY;
}
status = smb_raw_session_setup(session, mem_ctx, &setup);
if (!NT_STATUS_IS_OK(status)) {
- smbcli_session_close(session);
+ talloc_free(session);
talloc_free(mem_ctx);
return status;
}
tree = smbcli_tree_init(session);
if (!tree) {
- smbcli_session_close(session);
+ talloc_free(session);
talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
SAFE_FREE(in_path);
if (!NT_STATUS_IS_OK(status)) {
- smbcli_tree_close(tree);
+ talloc_free(tree);
talloc_free(mem_ctx);
return status;
}
c.close.in.fnum = smb->fnum;
c.close.in.write_time = 0;
smb_raw_close(smb->tree, &c);
- smbcli_tree_close(smb->tree);
+ talloc_free(smb->tree);
return NT_STATUS_OK;
}
smb->tree = tree;
(*p)->transport.private = smb;
- tree->reference_count++;
+ talloc_increase_ref_count(tree);
return NT_STATUS_OK;
}
/* this ensures that the reference count is decremented so
a pipe close will really close the link */
- smbcli_tree_close(cli->tree);
+ talloc_free(cli->tree);
(*p)->flags = binding->flags;
struct cvfs_private *private = tcon->ntvfs_private_list[depth];
smb_tree_disconnect(private->tree);
- smbcli_tree_close(private->tree);
+ talloc_free(private->tree);
return NT_STATUS_OK;
}
}
/*
- exit - closing files?
+ exit - closing files open by the pid
*/
static NTSTATUS cvfs_exit(struct smbsrv_request *req)
{
- return NT_STATUS_NOT_SUPPORTED;
+ NTVFS_GET_PRIVATE(cvfs_private, private, req);
+ struct smbcli_request *c_req;
+
+ if (!req->async.send_fn) {
+ return smb_raw_exit(private->tree->session);
+ }
+
+ c_req = smb_raw_exit_send(private->tree->session);
+
+ SIMPLE_ASYNC_TAIL;
+}
+
+/*
+ logoff - closing files open by the user
+*/
+static NTSTATUS cvfs_logoff(struct smbsrv_request *req)
+{
+ /* we can't do this right in the cifs backend .... */
+ return NT_STATUS_OK;
}
/*
ops.search_next = cvfs_search_next;
ops.search_close = cvfs_search_close;
ops.trans = cvfs_trans;
+ ops.logoff = cvfs_logoff;
if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
ops.trans2 = cvfs_trans2;
uint16_t fnum;
struct dcesrv_connection *dce_conn;
uint16_t ipc_state;
+ /* we need to remember the session it was opened on,
+ as it is illegal to operate on someone elses fnum */
+ struct smbsrv_session *session;
+
+ /* we need to remember the client pid that
+ opened the file so SMBexit works */
+ uint16_t smbpid;
} *pipe_list;
};
DLIST_ADD(private->pipe_list, p);
+ p->smbpid = req->smbpid;
+ p->session = req->session;
+
*ps = p;
return NT_STATUS_OK;
}
/*
- exit - closing files?
+ exit - closing files
*/
static NTSTATUS ipc_exit(struct smbsrv_request *req)
{
- return NT_STATUS_ACCESS_DENIED;
+ NTVFS_GET_PRIVATE(ipc_private, private, req);
+ struct pipe_state *p, *next;
+
+ for (p=private->pipe_list; p; p=next) {
+ next = p->next;
+ if (p->smbpid == req->smbpid) {
+ pipe_shutdown(private, p);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ logoff - closing files open by the user
+*/
+static NTSTATUS ipc_logoff(struct smbsrv_request *req)
+{
+ NTVFS_GET_PRIVATE(ipc_private, private, req);
+ struct pipe_state *p, *next;
+
+ for (p=private->pipe_list; p; p=next) {
+ next = p->next;
+ if (p->session == req->session) {
+ pipe_shutdown(private, p);
+ }
+ }
+
+ return NT_STATUS_OK;
}
/*
ops.search_next = ipc_search_next;
ops.search_close = ipc_search_close;
ops.trans = ipc_trans;
+ ops.logoff = ipc_logoff;
/* register ourselves with the NTVFS subsystem. */
ret = register_backend("ntvfs", &ops);
return status;
}
+/*
+ logoff - closing files
+*/
+static NTSTATUS nbench_logoff(struct smbsrv_request *req)
+{
+ NTVFS_GET_PRIVATE(nbench_private, private, req);
+ NTSTATUS status;
+
+ PASS_THRU_REQ(req, logoff, (req));
+
+ return status;
+}
+
/*
lock a byte range
*/
ops.search_next = nbench_search_next;
ops.search_close = nbench_search_close;
ops.trans = nbench_trans;
+ ops.logoff = nbench_logoff;
/* we don't register a trans2 handler as we want to be able to
log individual trans2 requests */
/* trans interface - used by IPC backend for pipes and RAP calls */
NTSTATUS (*trans)(struct smbsrv_request *req, struct smb_trans2 *trans);
+
+ /* logoff - called when a vuid is closed */
+ NTSTATUS (*logoff)(struct smbsrv_request *req);
};
/*
find open file handle given fnum
*/
-struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, uint16_t fnum)
+struct pvfs_file *pvfs_find_fd(struct smbsrv_request *req, uint16_t fnum)
{
+ NTVFS_GET_PRIVATE(pvfs_state, pvfs, req);
struct pvfs_file *f;
for (f=pvfs->open_files;f;f=f->next) {
if (f->fnum == fnum) {
+ if (req->session != f->session) {
+ DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n", fnum));
+ return NULL;
+ }
return f;
}
}
f->fnum = fd;
f->fd = fd;
f->name = talloc_steal(f, name);
+ f->session = req->session;
+ f->smbpid = req->smbpid;
/* setup a destructor to avoid file descriptor leaks on
abnormal termination */
return NT_STATUS_INVALID_LEVEL;
}
- f = pvfs_find_fd(pvfs, io->close.in.fnum);
+ f = pvfs_find_fd(req, io->close.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
return status;
}
+
+/*
+ logoff - close all file descriptors open by a vuid
+*/
+NTSTATUS pvfs_logoff(struct smbsrv_request *req)
+{
+ NTVFS_GET_PRIVATE(pvfs_state, pvfs, req);
+ struct pvfs_file *f, *next;
+
+ for (f=pvfs->open_files;f;f=next) {
+ next = f->next;
+ if (f->session == req->session) {
+ talloc_set_destructor(f, NULL);
+ DLIST_REMOVE(pvfs->open_files, f);
+ talloc_free(f);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ exit - close files for the current pid
+*/
+NTSTATUS pvfs_exit(struct smbsrv_request *req)
+{
+ NTVFS_GET_PRIVATE(pvfs_state, pvfs, req);
+ struct pvfs_file *f, *next;
+
+ for (f=pvfs->open_files;f;f=next) {
+ next = f->next;
+ if (f->smbpid == req->smbpid) {
+ talloc_set_destructor(f, NULL);
+ DLIST_REMOVE(pvfs->open_files, f);
+ talloc_free(f);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
return ntvfs_map_qfileinfo(req, info, pvfs->ops);
}
- f = pvfs_find_fd(pvfs, info->generic.in.fnum);
+ f = pvfs_find_fd(req, info->generic.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
return NT_STATUS_NOT_SUPPORTED;
}
- f = pvfs_find_fd(pvfs, rd->readx.in.fnum);
+
+ f = pvfs_find_fd(req, rd->readx.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
struct utimbuf unix_times;
struct pvfs_file *f;
- f = pvfs_find_fd(pvfs, info->generic.file.fnum);
+ f = pvfs_find_fd(req, info->generic.file.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
switch (wr->generic.level) {
case RAW_WRITE_WRITEX:
- f = pvfs_find_fd(pvfs, wr->writex.in.fnum);
+ f = pvfs_find_fd(req, wr->writex.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
return NT_STATUS_OK;
case RAW_WRITE_WRITE:
- f = pvfs_find_fd(pvfs, wr->write.in.fnum);
+ f = pvfs_find_fd(req, wr->write.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
return NT_STATUS_NOT_IMPLEMENTED;
}
-/*
- exit - closing files?
-*/
-static NTSTATUS pvfs_exit(struct smbsrv_request *req)
-{
- DEBUG(0,("pvfs_exit not implemented\n"));
- return NT_STATUS_NOT_SUPPORTED;
-}
-
/*
lock a byte range
*/
ops.search_next = pvfs_search_next;
ops.search_close = pvfs_search_close;
ops.trans = pvfs_trans;
+ ops.logoff = pvfs_logoff;
/* register ourselves with the NTVFS subsystem. We register
under the name 'default' as we wish to be the default
int fd;
uint16_t fnum;
struct pvfs_filename *name;
+
+ /* we need to remember the session it was opened on,
+ as it is illegal to operate on someone elses fnum */
+ struct smbsrv_session *session;
+
+ /* we need to remember the client pid that
+ opened the file so SMBexit works */
+ uint16_t smbpid;
};
}
/*
- exit - closing files?
+ exit - closing files
*/
static NTSTATUS svfs_exit(struct smbsrv_request *req)
{
return NT_STATUS_NOT_SUPPORTED;
}
+/*
+ logoff - closing files
+*/
+static NTSTATUS svfs_logoff(struct smbsrv_request *req)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
/*
lock a byte range
*/
ops.search_next = svfs_search_next;
ops.search_close = svfs_search_close;
ops.trans = svfs_trans;
+ ops.logoff = svfs_logoff;
/* register ourselves with the NTVFS subsystem. We register
under names 'simple'
gensec_end(&p->auth_state.gensec_security);
}
- if (p->auth_state.session_info) {
- free_session_info(&p->auth_state.session_info);
- }
-
talloc_free(p);
}
/****************************************************************************
- Reply to a exit.
+ Reply to a exit. This closes all files open by a smbpid
****************************************************************************/
void reply_exit(struct smbsrv_request *req)
{
+ NTSTATUS status;
+ struct smbsrv_tcon *tcon;
REQ_CHECK_WCT(req, 0);
- req->async.send_fn = reply_simple_send;
-
- if (!req->tcon) {
- req_reply_error(req, NT_STATUS_INVALID_HANDLE);
- return;
+ for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
+ req->tcon = tcon;
+ status = tcon->ntvfs_ops->exit(req);
+ req->tcon = NULL;
+ if (!NT_STATUS_IS_OK(status)) {
+ req_reply_error(req, status);
+ return;
+ }
}
- /* call backend */
- req->async.status = req->tcon->ntvfs_ops->exit(req);
-
- REQ_ASYNC_TAIL;
+ req_setup_reply(req, 0, 0);
+ req_send_reply(req);
}
req_reply_error(req, NT_STATUS_FOOBAR);
}
-
/****************************************************************************
Reply to a SMBulogoffX.
****************************************************************************/
void reply_ulogoffX(struct smbsrv_request *req)
{
+ struct smbsrv_tcon *tcon;
uint16_t vuid;
+ NTSTATUS status;
vuid = SVAL(req->in.hdr, HDR_UID);
-
+
/* in user level security we are supposed to close any files
- open by this user */
+ open by this user on all open tree connects */
if ((vuid != 0) && (lp_security() != SEC_SHARE)) {
- DEBUG(0,("REWRITE: not closing user files\n"));
+ for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
+ req->tcon = tcon;
+ status = tcon->ntvfs_ops->logoff(req);
+ req->tcon = NULL;
+ if (!NT_STATUS_IS_OK(status)) {
+ req_reply_error(req, status);
+ return;
+ }
+ }
}
smbsrv_invalidate_vuid(req->smb_conn, vuid);
return False;
}
- smbcli_session_close(session);
+ talloc_free(session);
talloc_free(mem_ctx);
return True;
printf("create a second security context on the same transport\n");
session = smbcli_session_init(cli->transport);
+ talloc_increase_ref_count(cli->transport);
+
setup.generic.level = RAW_SESSSETUP_GENERIC;
setup.generic.in.sesskey = cli->transport->negotiate.sesskey;
setup.generic.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
printf("create a third security context on the same transport, with vuid set\n");
session2 = smbcli_session_init(cli->transport);
+ talloc_increase_ref_count(cli->transport);
+
session2->vuid = session->vuid;
setup.generic.level = RAW_SESSSETUP_GENERIC;
setup.generic.in.sesskey = cli->transport->negotiate.sesskey;
printf("vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid);
CHECK_NOT_VALUE(session->vuid, session2->vuid);
+ talloc_free(session2);
if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
printf("create a fourth security context on the same transport, without extended security\n");
session3 = smbcli_session_init(cli->transport);
+ talloc_increase_ref_count(cli->transport);
+
session3->vuid = session->vuid;
setup.generic.level = RAW_SESSSETUP_GENERIC;
setup.generic.in.sesskey = cli->transport->negotiate.sesskey;
status = smb_raw_session_setup(session3, mem_ctx, &setup);
CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ talloc_free(session3);
}
printf("use the same tree as the existing connection\n");
tree = smbcli_tree_init(session);
+ talloc_increase_ref_count(session);
tree->tid = cli->tree->tid;
- cli->tree->reference_count++;
printf("create a file using the new vuid\n");
io.generic.level = RAW_OPEN_NTCREATEX;
printf("logoff the new vuid\n");
status = smb_raw_ulogoff(session);
CHECK_STATUS(status, NT_STATUS_OK);
+ talloc_free(session);
printf("the new vuid should not now be accessible\n");
status = smb_raw_write(tree, &wr);
/* close down the new tree, which will also close the session
as the reference count will be 0 */
- smbcli_tree_close(tree);
+ talloc_free(tree);
done:
return ret;
}
share = lp_parm_string(-1, "torture", "share");
-
+
printf("create a second tree context on the same session\n");
tree = smbcli_tree_init(cli->session);
+ talloc_increase_ref_count(cli->session);
tcon.generic.level = RAW_TCON_TCONX;
tcon.tconx.in.flags = 0;
CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
/* close down the new tree */
- smbcli_tree_close(tree);
+ talloc_free(tree);
done:
return ret;
torture_close_connection(cli);
talloc_destroy(mem_ctx);
+
return ret;
}