#include "auth.h"
#include "smbprofile.h"
#include "../lib/tsocket/tsocket.h"
+#include "lib/tevent_wait.h"
+#include "libcli/smb/smb_signing.h"
/****************************************************************************
Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
set_local_machine_name(name1, True);
set_remote_machine_name(name2, True);
+ if (is_ipaddress(sconn->remote_hostname)) {
+ char *p = discard_const_p(char, sconn->remote_hostname);
+
+ talloc_free(p);
+
+ sconn->remote_hostname = talloc_strdup(sconn,
+ get_remote_machine_name());
+ if (sconn->remote_hostname == NULL) {
+ exit_server_cleanly("could not copy remote name");
+ }
+ sconn->conn->remote_hostname = sconn->remote_hostname;
+ }
+
DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
get_local_machine_name(), get_remote_machine_name(),
name_type2));
const char *p;
TALLOC_CTX *ctx = talloc_tos();
struct smbd_server_connection *sconn = req->sconn;
+ NTTIME now = timeval_to_nttime(&req->request_time);
START_PROFILE(SMBtcon);
service = service_buf;
}
- conn = make_connection(sconn,service,dev,
+ conn = make_connection(sconn, now, service, dev,
req->vuid,&nt_status);
req->conn = conn;
int passlen;
char *path = NULL;
const char *p, *q;
- uint16 tcon_flags;
+ uint16_t tcon_flags;
+ struct smbXsrv_session *session = NULL;
+ NTTIME now = timeval_to_nttime(&req->request_time);
+ bool session_key_updated = false;
+ uint16_t optional_support = 0;
struct smbd_server_connection *sconn = req->sconn;
START_PROFILE(SMBtconX);
tcon_flags = SVAL(req->vwv+2, 0);
/* we might have to close an old one */
- if ((tcon_flags & 0x1) && conn) {
+ if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
struct smbXsrv_tcon *tcon;
NTSTATUS status;
DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
- conn = make_connection(sconn, service, client_devicetype,
+ nt_status = smb1srv_session_lookup(req->sconn->conn,
+ req->vuid, now, &session);
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
+ reply_force_doserror(req, ERRSRV, ERRbaduid);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+ reply_nterror(req, nt_status);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ if (session->global->auth_session_info == NULL) {
+ reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ /*
+ * If there is no application key defined yet
+ * we create one.
+ *
+ * This means we setup the application key on the
+ * first tcon that happens via the given session.
+ *
+ * Once the application key is defined, it does not
+ * change any more.
+ */
+ if (session->global->application_key.length == 0 &&
+ session->global->signing_key.length > 0)
+ {
+ struct smbXsrv_session *x = session;
+ struct auth_session_info *session_info =
+ session->global->auth_session_info;
+ uint8_t session_key[16];
+
+ ZERO_STRUCT(session_key);
+ memcpy(session_key, x->global->signing_key.data,
+ MIN(x->global->signing_key.length, sizeof(session_key)));
+
+ /*
+ * The application key is truncated/padded to 16 bytes
+ */
+ x->global->application_key = data_blob_talloc(x->global,
+ session_key,
+ sizeof(session_key));
+ ZERO_STRUCT(session_key);
+ if (x->global->application_key.data == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+
+ if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
+ smb_key_derivation(x->global->application_key.data,
+ x->global->application_key.length,
+ x->global->application_key.data);
+ optional_support |= SMB_EXTENDED_SIGNATURES;
+ }
+
+ /*
+ * Place the application key into the session_info
+ */
+ data_blob_clear_free(&session_info->session_key);
+ session_info->session_key = data_blob_dup_talloc(session_info,
+ x->global->application_key);
+ if (session_info->session_key.data == NULL) {
+ data_blob_clear_free(&x->global->application_key);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBtconX);
+ return;
+ }
+ session_key_updated = true;
+ }
+
+ conn = make_connection(sconn, now, service, client_devicetype,
req->vuid, &nt_status);
req->conn =conn;
if (!conn) {
+ if (session_key_updated) {
+ struct smbXsrv_session *x = session;
+ struct auth_session_info *session_info =
+ session->global->auth_session_info;
+ data_blob_clear_free(&x->global->application_key);
+ data_blob_clear_free(&session_info->session_key);
+ }
reply_nterror(req, nt_status);
END_PROFILE(SMBtconX);
return;
/* what does setting this bit do? It is set by NT4 and
may affect the ability to autorun mounted cdroms */
- SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
- (lp_csc_policy(SNUM(conn)) << 2));
+ optional_support |= SMB_SUPPORT_SEARCH_BITS;
+ optional_support |=
+ (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
DEBUG(2,("Serving %s as a Dfs root\n",
lp_servicename(ctx, SNUM(conn)) ));
- SSVAL(req->outbuf, smb_vwv2,
- SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
+ optional_support |= SMB_SHARE_IN_DFS;
}
+
+ SSVAL(req->outbuf, smb_vwv2, optional_support);
}
SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
START_PROFILE(SMBreadbraw);
- if (srv_is_signing_active(sconn) ||
- is_encrypted_packet(sconn, req->inbuf)) {
+ if (srv_is_signing_active(sconn) || req->encrypted) {
exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
"raw reads/writes are disallowed.");
}
*/
if (!req_is_in_chain(req) &&
- !is_encrypted_packet(req->sconn, req->inbuf) &&
+ !req->encrypted &&
(fsp->base_fsp == NULL) &&
(fsp->wcp == NULL) &&
lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
return;
}
+/****************************************************************************
+ Work out how much space we have for a read return.
+****************************************************************************/
+
+static size_t calc_max_read_pdu(const struct smb_request *req)
+{
+ if (req->sconn->conn->protocol < PROTOCOL_NT1) {
+ return req->sconn->smb1.sessions.max_send;
+ }
+
+ if (!lp_large_readwrite()) {
+ return req->sconn->smb1.sessions.max_send;
+ }
+
+ if (req_is_in_chain(req)) {
+ return req->sconn->smb1.sessions.max_send;
+ }
+
+ if (req->encrypted) {
+ /*
+ * Don't take encrypted traffic up to the
+ * limit. There are padding considerations
+ * that make that tricky.
+ */
+ return req->sconn->smb1.sessions.max_send;
+ }
+
+ if (srv_is_signing_active(req->sconn)) {
+ return 0x1FFFF;
+ }
+
+ if (!lp_unix_extensions()) {
+ return 0x1FFFF;
+ }
+
+ /*
+ * We can do ultra-large POSIX reads.
+ */
+ return 0xFFFFFF;
+}
+
+/****************************************************************************
+ Calculate how big a read can be. Copes with all clients. It's always
+ safe to return a short read - Windows does this.
+****************************************************************************/
+
+static size_t calc_read_size(const struct smb_request *req,
+ size_t upper_size,
+ size_t lower_size)
+{
+ size_t max_pdu = calc_max_read_pdu(req);
+ size_t total_size = 0;
+ size_t hdr_len = MIN_SMB_SIZE + VWV(12);
+ size_t max_len = max_pdu - hdr_len;
+
+ /*
+ * Windows explicitly ignores upper size of 0xFFFF.
+ * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
+ * We must do the same as these will never fit even in
+ * an extended size NetBIOS packet.
+ */
+ if (upper_size == 0xFFFF) {
+ upper_size = 0;
+ }
+
+ if (req->sconn->conn->protocol < PROTOCOL_NT1) {
+ upper_size = 0;
+ }
+
+ total_size = ((upper_size<<16) | lower_size);
+
+ /*
+ * LARGE_READX test shows it's always safe to return
+ * a short read. Windows does so.
+ */
+ return MIN(total_size, max_len);
+}
+
/****************************************************************************
Reply to a read and X.
****************************************************************************/
void reply_read_and_X(struct smb_request *req)
{
- struct smbd_server_connection *sconn = req->sconn;
connection_struct *conn = req->conn;
files_struct *fsp;
off_t startpos;
size_t smb_maxcnt;
+ size_t upper_size;
bool big_readX = False;
#if 0
size_t smb_mincnt = SVAL(req->vwv+6, 0);
return;
}
- if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
- (get_remote_arch() == RA_SAMBA)) {
+ upper_size = SVAL(req->vwv+7, 0);
+ smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
+ if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
/*
- * This is Samba only behavior (up to Samba 3.6)!
- *
- * Windows 2008 R2 ignores the upper_size,
- * so we do unless unix extentions are active
- * or "smbclient" is talking to us.
+ * This is a heuristic to avoid keeping large
+ * outgoing buffers around over long-lived aio
+ * requests.
*/
- size_t upper_size = SVAL(req->vwv+7, 0);
- smb_maxcnt |= (upper_size<<16);
- if (upper_size > 1) {
- /* Can't do this on a chained packet. */
- if ((CVAL(req->vwv+0, 0) != 0xFF)) {
- reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
- END_PROFILE(SMBreadX);
- return;
- }
- /* We currently don't do this on signed or sealed data. */
- if (srv_is_signing_active(req->sconn) ||
- is_encrypted_packet(req->sconn, req->inbuf)) {
- reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
- END_PROFILE(SMBreadX);
- return;
- }
- /* Is there room in the reply for this data ? */
- if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
- reply_nterror(req,
- NT_STATUS_INVALID_PARAMETER);
- END_PROFILE(SMBreadX);
- return;
- }
- big_readX = True;
- }
+ big_readX = True;
}
if (req->wct == 12) {
return;
}
+struct reply_close_state {
+ files_struct *fsp;
+ struct smb_request *smbreq;
+};
+
+static void do_smb1_close(struct tevent_req *req);
+
void reply_close(struct smb_request *req)
{
connection_struct *conn = req->conn;
set_close_write_time(fsp, convert_time_t_to_timespec(t));
}
+ if (fsp->num_aio_requests != 0) {
+
+ struct reply_close_state *state;
+
+ DEBUG(10, ("closing with aio %u requests pending\n",
+ fsp->num_aio_requests));
+
+ /*
+ * We depend on the aio_extra destructor to take care of this
+ * close request once fsp->num_aio_request drops to 0.
+ */
+
+ fsp->deferred_close = tevent_wait_send(
+ fsp, fsp->conn->sconn->ev_ctx);
+ if (fsp->deferred_close == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ state = talloc(fsp, struct reply_close_state);
+ if (state == NULL) {
+ TALLOC_FREE(fsp->deferred_close);
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ state->fsp = fsp;
+ state->smbreq = talloc_move(fsp, &req);
+ tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
+ state);
+ END_PROFILE(SMBclose);
+ return;
+ }
+
/*
* close_file() returns the unix errno if an error was detected on
* close - normally this is due to a disk full error. If not then it
*/
status = close_file(req, fsp, NORMAL_CLOSE);
-
+done:
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
END_PROFILE(SMBclose);
return;
}
+static void do_smb1_close(struct tevent_req *req)
+{
+ struct reply_close_state *state = tevent_req_callback_data(
+ req, struct reply_close_state);
+ struct smb_request *smbreq;
+ NTSTATUS status;
+ int ret;
+
+ ret = tevent_wait_recv(req);
+ TALLOC_FREE(req);
+ if (ret != 0) {
+ DEBUG(10, ("tevent_wait_recv returned %s\n",
+ strerror(ret)));
+ /*
+ * Continue anyway, this should never happen
+ */
+ }
+
+ /*
+ * fsp->smb2_close_request right now is a talloc grandchild of
+ * fsp. When we close_file(fsp), it would go with it. No chance to
+ * reply...
+ */
+ smbreq = talloc_move(talloc_tos(), &state->smbreq);
+
+ status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
+ if (NT_STATUS_IS_OK(status)) {
+ reply_outbuf(smbreq, 0, 0);
+ } else {
+ reply_nterror(smbreq, status);
+ }
+ if (!srv_send_smb(smbreq->sconn,
+ (char *)smbreq->outbuf,
+ true,
+ smbreq->seqnum+1,
+ IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
+ NULL)) {
+ exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
+ "failed.");
+ }
+ TALLOC_FREE(smbreq);
+}
+
/****************************************************************************
Reply to a writeclose (Core+ protocol).
****************************************************************************/
"%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
smb_fname_str_dbg(smb_fname_dst)));
- if (!lp_posix_pathnames() &&
+ if (!fsp->is_directory &&
+ !lp_posix_pathnames() &&
(lp_map_archive(SNUM(conn)) ||
lp_store_dos_attributes(SNUM(conn)))) {
/* We must set the archive bit on the newly
long offset = 0;
int create_options = 0;
bool posix_pathnames = lp_posix_pathnames();
+ int rc;
/*
* Split the old name into directory and last component
ZERO_STRUCT(smb_fname_src->st);
if (posix_pathnames) {
- SMB_VFS_LSTAT(conn, smb_fname_src);
+ rc = SMB_VFS_LSTAT(conn, smb_fname_src);
} else {
- SMB_VFS_STAT(conn, smb_fname_src);
+ rc = SMB_VFS_STAT(conn, smb_fname_src);
+ }
+ if (rc == -1) {
+ status = map_nt_error_from_unix_common(errno);
+ goto out;
}
if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {