#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
char **pp_dest, const char *src, int flags,
NTSTATUS *err, bool *contains_wcard)
{
- return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
- pp_dest, src, smbreq_bufrem(req, src),
- flags, err, contains_wcard);
+ ssize_t bufrem = smbreq_bufrem(req, src);
+
+ if (bufrem < 0) {
+ *err = NT_STATUS_INVALID_PARAMETER;
+ return 0;
+ }
+
+ return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
+ req->flags2, pp_dest, src, bufrem, flags,
+ err, contains_wcard);
}
size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
flags, err, &ignore);
}
+/**
+ * pull a string from the smb_buf part of a packet. In this case the
+ * string can either be null terminated or it can be terminated by the
+ * end of the smbbuf area
+ */
+size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
+ char **dest, const uint8_t *src, int flags)
+{
+ ssize_t bufrem = smbreq_bufrem(req, src);
+
+ if (bufrem < 0) {
+ return 0;
+ }
+
+ return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
+ bufrem, flags);
+}
+
/****************************************************************************
Check if we have a correct fsp pointing to a file. Basic check for open fsp.
****************************************************************************/
return true;
}
-static bool netbios_session_retarget(struct smbd_server_connection *sconn,
+static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
const char *name, int name_type)
{
+ struct smbd_server_connection *sconn = xconn->sconn;
char *trim_name;
char *trim_name_type;
const char *retarget_parm;
bool ret = false;
uint8_t outbuf[10];
- if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
+ if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
return false;
}
Reply to a (netbios-level) special message.
****************************************************************************/
-void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
+void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
{
+ struct smbd_server_connection *sconn = xconn->sconn;
int msg_type = CVAL(inbuf,0);
int msg_flags = CVAL(inbuf,1);
/*
*name1 = *name2 = 0;
- if (sconn->nbt.got_session) {
+ if (xconn->transport.nbt.got_session) {
exit_server_cleanly("multiple session request not permitted");
}
DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
name1, name_type1, name2, name_type2));
- if (netbios_session_retarget(sconn, name1, name_type1)) {
+ if (netbios_session_retarget(xconn, name1, name_type1)) {
exit_server_cleanly("retargeted client");
}
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");
+ }
+ xconn->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));
reload_services(sconn, conn_snum_used, true);
reopen_logs();
- sconn->nbt.got_session = true;
+ xconn->transport.nbt.got_session = true;
break;
}
char *dev = NULL;
int pwlen=0;
NTSTATUS nt_status;
- const char *p;
+ const uint8_t *p;
+ const char *p2;
TALLOC_CTX *ctx = talloc_tos();
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
+ struct smbd_server_connection *sconn = xconn->sconn;
+ NTTIME now = timeval_to_nttime(&req->request_time);
START_PROFILE(SMBtcon);
return;
}
- p = (const char *)req->buf + 1;
+ p = req->buf + 1;
p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
p += 1;
pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
END_PROFILE(SMBtcon);
return;
}
- p = strrchr_m(service_buf,'\\');
- if (p) {
- service = p+1;
+ p2 = strrchr_m(service_buf,'\\');
+ if (p2) {
+ service = p2+1;
} else {
service = service_buf;
}
- conn = make_connection(sconn,service,dev,
+ conn = make_connection(sconn, now, service, dev,
req->vuid,&nt_status);
req->conn = conn;
}
reply_outbuf(req, 2, 0);
- SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
+ SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
SSVAL(req->outbuf,smb_vwv1,conn->cnum);
SSVAL(req->outbuf,smb_tid,conn->cnum);
NTSTATUS nt_status;
int passlen;
char *path = NULL;
- const char *p, *q;
- uint16 tcon_flags;
- struct smbd_server_connection *sconn = req->sconn;
+ const uint8_t *p;
+ const char *q;
+ 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 smbXsrv_connection *xconn = req->xconn;
+ struct smbd_server_connection *sconn = xconn->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;
return;
}
- if (sconn->smb1.negprot.encrypted_passwords) {
- p = (const char *)req->buf + passlen;
+ if (xconn->smb1.negprot.encrypted_passwords) {
+ p = req->buf + passlen;
} else {
- p = (const char *)req->buf + passlen + 1;
+ p = req->buf + passlen + 1;
}
p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
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(xconn,
+ 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(SNUM(conn)) ));
- SSVAL(req->outbuf, smb_vwv2,
- SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
+ lp_servicename(ctx, SNUM(conn)) ));
+ optional_support |= SMB_SHARE_IN_DFS;
}
+
+ SSVAL(req->outbuf, smb_vwv2, optional_support);
}
SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
STR_TERMINATE|STR_ASCII);
if (conn) {
srvstr_push((char *)req->outbuf, req->flags2,
- p+18, lp_servicename(SNUM(conn)),
+ p+18,
+ lp_servicename(talloc_tos(),
+ SNUM(conn)),
13, STR_TERMINATE|STR_ASCII);
} else {
memset(p+18, 0, 13);
TALLOC_CTX *ctx = talloc_tos();
bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
struct dptr_struct *dirptr = NULL;
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
+ struct smbd_server_connection *sconn = xconn->sconn;
START_PROFILE(SMBsearch);
if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
char buf[DIR_STRUCT_SIZE];
memcpy(buf,status,21);
- if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
+ if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
reply_nterror(req, NT_STATUS_NO_MEMORY);
goto out;
}
} else {
unsigned int i;
- maxentries = MIN(
- maxentries,
- ((BUFFER_SIZE -
- ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
- /DIR_STRUCT_SIZE));
+ size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
+ size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
+
+ maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- directory,lp_dontdescend(SNUM(conn))));
- if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
+ directory,lp_dont_descend(ctx, SNUM(conn))));
+ if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
check_descend = True;
}
uint32 create_options = 0;
uint32_t private_flags = 0;
NTSTATUS status;
- bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBopen);
goto out;
}
+ if (!map_open_params_to_ntcreate(fname, deny_mode,
+ OPENX_FILE_EXISTS_OPEN, &access_mask,
+ &share_mode, &create_disposition,
+ &create_options, &private_flags)) {
+ reply_force_doserror(req, ERRDOS, ERRbadaccess);
+ goto out;
+ }
+
status = filename_convert(ctx,
conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ UCF_PREP_CREATEFILE,
NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
- if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
- OPENX_FILE_EXISTS_OPEN, &access_mask,
- &share_mode, &create_disposition,
- &create_options, &private_flags)) {
- reply_force_doserror(req, ERRDOS, ERRbadaccess);
- goto out;
- }
-
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
create_options, /* create_options */
dos_attr, /* file_attributes */
oplock_request, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
private_flags,
NULL, /* sd */
goto out;
}
+ /* Ensure we're pointing at the correct stat struct. */
+ TALLOC_FREE(smb_fname);
+ smb_fname = fsp->fsp_name;
+
size = smb_fname->st.st_ex_size;
fattr = dos_mode(conn, smb_fname);
- /* Deal with other possible opens having a modified
- write time. JRA. */
- if (ask_sharemode) {
- struct timespec write_time_ts;
-
- ZERO_STRUCT(write_time_ts);
- get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
- if (!null_timespec(write_time_ts)) {
- update_stat_ex_mtime(&smb_fname->st, write_time_ts);
- }
- }
-
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
}
out:
- TALLOC_FREE(smb_fname);
END_PROFILE(SMBopen);
return;
}
goto out;
}
+ if (!map_open_params_to_ntcreate(fname, deny_mode,
+ smb_ofun,
+ &access_mask, &share_mode,
+ &create_disposition,
+ &create_options,
+ &private_flags)) {
+ reply_force_doserror(req, ERRDOS, ERRbadaccess);
+ goto out;
+ }
+
status = filename_convert(ctx,
conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ UCF_PREP_CREATEFILE,
NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
- if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
- smb_ofun,
- &access_mask, &share_mode,
- &create_disposition,
- &create_options,
- &private_flags)) {
- reply_force_doserror(req, ERRDOS, ERRbadaccess);
- goto out;
- }
-
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
create_options, /* create_options */
smb_attr, /* file_attributes */
oplock_request, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
private_flags,
NULL, /* sd */
conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ UCF_PREP_CREATEFILE,
NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
create_options, /* create_options */
fattr, /* file_attributes */
oplock_request, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
{
connection_struct *conn = req->conn;
struct smb_filename *smb_fname = NULL;
+ char *wire_name = NULL;
char *fname = NULL;
uint32 fattr;
files_struct *fsp;
int oplock_request;
- int tmpfd;
char *s;
NTSTATUS status;
+ int i;
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBctemp);
fattr = SVAL(req->vwv+0, 0);
oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
- srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
+ srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
goto out;
}
- if (*fname) {
- fname = talloc_asprintf(ctx,
- "%s/TMXXXXXX",
- fname);
- } else {
- fname = talloc_strdup(ctx, "TMXXXXXX");
- }
- if (!fname) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
+ for (i = 0; i < 10; i++) {
+ if (*wire_name) {
+ fname = talloc_asprintf(ctx,
+ "%s/TMP%s",
+ wire_name,
+ generate_random_str_list(ctx, 5, "0123456789"));
+ } else {
+ fname = talloc_asprintf(ctx,
+ "TMP%s",
+ generate_random_str_list(ctx, 5, "0123456789"));
+ }
- status = filename_convert(ctx, conn,
+ if (!fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
+ status = filename_convert(ctx, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
+ UCF_PREP_CREATEFILE,
NULL,
&smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
- reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
ERRSRV, ERRbadpath);
+ goto out;
+ }
+ reply_nterror(req, status);
goto out;
}
- reply_nterror(req, status);
- goto out;
- }
-
- tmpfd = mkstemp(smb_fname->base_name);
- if (tmpfd == -1) {
- reply_nterror(req, map_nt_error_from_unix(errno));
- goto out;
- }
- SMB_VFS_STAT(conn, smb_fname);
-
- /* We should fail if file does not exist. */
- status = SMB_VFS_CREATE_FILE(
- conn, /* conn */
- req, /* req */
- 0, /* root_dir_fid */
- smb_fname, /* fname */
- FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
- FILE_OPEN, /* create_disposition*/
- 0, /* create_options */
- fattr, /* file_attributes */
- oplock_request, /* oplock_request */
- 0, /* allocation_size */
- 0, /* private_flags */
- NULL, /* sd */
- NULL, /* ea_list */
- &fsp, /* result */
- NULL); /* pinfo */
-
- /* close fd from mkstemp() */
- close(tmpfd);
+ /* Create the file. */
+ status = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_fname, /* fname */
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
+ FILE_CREATE, /* create_disposition*/
+ 0, /* create_options */
+ fattr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ NULL, /* lease */
+ 0, /* allocation_size */
+ 0, /* private_flags */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL); /* pinfo */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ TALLOC_FREE(fname);
+ TALLOC_FREE(smb_fname);
+ continue;
+ }
- if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->sconn, req->mid)) {
- /* We have re-scheduled this call. */
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
+ /* We have re-scheduled this call. */
+ goto out;
+ }
+ reply_openerror(req, status);
goto out;
}
- reply_openerror(req, status);
+
+ break;
+ }
+
+ if (i == 10) {
+ /* Collision after 10 times... */
+ reply_nterror(req, status);
goto out;
}
fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
out:
TALLOC_FREE(smb_fname);
+ TALLOC_FREE(wire_name);
END_PROFILE(SMBctemp);
return;
}
return NT_STATUS_NO_SUCH_FILE;
}
- if (!dir_check_ftype(conn, fattr, dirtype)) {
+ if (!dir_check_ftype(fattr, dirtype)) {
if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
FILE_ATTRIBUTE_NORMAL,
0, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
status = do_unlink(conn, req, smb_fname, dirtype);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(dir_hnd);
TALLOC_FREE(frame);
TALLOC_FREE(talloced);
- continue;
+ goto out;
}
count++;
Fake (read/write) sendfile. Returns -1 on read or write fail.
****************************************************************************/
-ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
+ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
+ off_t startpos, size_t nread)
{
size_t bufsize;
size_t tosend = nread;
memset(buf + ret, '\0', cur_read - ret);
}
- if (write_data(fsp->conn->sconn->sock, buf, cur_read)
- != cur_read) {
- char addr[INET6_ADDRSTRLEN];
+ ret = write_data(xconn->transport.sock, buf, cur_read);
+ if (ret != cur_read) {
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
DEBUG(0, ("write_data failed for client %s. "
"Error %s\n",
- get_peer_addr(fsp->conn->sconn->sock, addr,
- sizeof(addr)),
- strerror(errno)));
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
SAFE_FREE(buf);
+ errno = saved_errno;
return -1;
}
tosend -= cur_read;
/****************************************************************************
Deal with the case of sendfile reading less bytes from the file than
- requested. Fill with zeros (all we can do).
+ requested. Fill with zeros (all we can do). Returns 0 on success
****************************************************************************/
-void sendfile_short_send(files_struct *fsp,
- ssize_t nread,
- size_t headersize,
- size_t smb_maxcnt)
+ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
+ files_struct *fsp,
+ ssize_t nread,
+ size_t headersize,
+ size_t smb_maxcnt)
{
#define SHORT_SEND_BUFSIZE 1024
if (nread < headersize) {
DEBUG(0,("sendfile_short_send: sendfile failed to send "
"header for file %s (%s). Terminating\n",
fsp_str_dbg(fsp), strerror(errno)));
- exit_server_cleanly("sendfile_short_send failed");
+ return -1;
}
nread -= headersize;
if (nread < smb_maxcnt) {
char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
if (!buf) {
- exit_server_cleanly("sendfile_short_send: "
- "malloc failed");
+ DEBUG(0,("sendfile_short_send: malloc failed "
+ "for file %s (%s). Terminating\n",
+ fsp_str_dbg(fsp), strerror(errno)));
+ return -1;
}
DEBUG(0,("sendfile_short_send: filling truncated file %s "
* about efficiency here :-)
*/
size_t to_write;
+ ssize_t ret;
to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
- if (write_data(fsp->conn->sconn->sock, buf, to_write)
- != to_write) {
- char addr[INET6_ADDRSTRLEN];
+ ret = write_data(xconn->transport.sock, buf, to_write);
+ if (ret != to_write) {
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
DEBUG(0, ("write_data failed for client %s. "
"Error %s\n",
- get_peer_addr(
- fsp->conn->sconn->sock, addr,
- sizeof(addr)),
- strerror(errno)));
- exit_server_cleanly("sendfile_short_send: "
- "write_data failed");
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
+ return -1;
}
nread += to_write;
}
SAFE_FREE(buf);
}
+
+ return 0;
}
/****************************************************************************
Return a readbraw error (4 bytes of zero).
****************************************************************************/
-static void reply_readbraw_error(struct smbd_server_connection *sconn)
+static void reply_readbraw_error(struct smbXsrv_connection *xconn)
{
char header[4];
SIVAL(header,0,0);
- smbd_lock_socket(sconn);
- if (write_data(sconn->sock,header,4) != 4) {
- char addr[INET6_ADDRSTRLEN];
+ smbd_lock_socket(xconn);
+ if (write_data(xconn->transport.sock,header,4) != 4) {
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
DEBUG(0, ("write_data failed for client %s. "
"Error %s\n",
- get_peer_addr(sconn->sock, addr, sizeof(addr)),
- strerror(errno)));
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
fail_readraw();
}
- smbd_unlock_socket(sconn);
+ smbd_unlock_socket(xconn);
}
/****************************************************************************
size_t nread,
ssize_t mincount)
{
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
char *outbuf = NULL;
ssize_t ret=0;
if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
(fsp->wcp == NULL) &&
- lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
+ lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
ssize_t sendfile_read = -1;
char header[4];
DATA_BLOB header_blob;
_smb_setlen(header,nread);
header_blob = data_blob_const(header, 4);
- sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
+ sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
&header_blob, startpos,
nread);
if (sendfile_read == -1) {
set_use_sendfile(SNUM(conn), False);
DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
- if (fake_sendfile(fsp, startpos, nread) == -1) {
+ if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
DEBUG(0,("send_file_readbraw: "
"fake_sendfile failed for "
"file %s (%s).\n",
/* Deal with possible short send. */
if (sendfile_read != 4+nread) {
- sendfile_short_send(fsp, sendfile_read, 4, nread);
+ ret = sendfile_short_send(xconn, fsp,
+ sendfile_read, 4, nread);
+ if (ret == -1) {
+ fail_readraw();
+ }
}
return;
}
if (!outbuf) {
DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
(unsigned)(nread+4)));
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
return;
}
}
_smb_setlen(outbuf,ret);
- if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
- char addr[INET6_ADDRSTRLEN];
+ if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
- DEBUG(0, ("write_data failed for client %s. "
- "Error %s\n",
- get_peer_addr(fsp->conn->sconn->sock, addr,
- sizeof(addr)),
- strerror(errno)));
+ DEBUG(0, ("write_data failed for client %s. Error %s\n",
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
fail_readraw();
}
void reply_readbraw(struct smb_request *req)
{
connection_struct *conn = req->conn;
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
ssize_t maxcount,mincount;
size_t nread = 0;
off_t startpos;
START_PROFILE(SMBreadbraw);
- if (srv_is_signing_active(sconn) ||
- is_encrypted_packet(sconn, req->inbuf)) {
+ if (srv_is_signing_active(xconn) || req->encrypted) {
exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
"raw reads/writes are disallowed.");
}
if (req->wct < 8) {
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
- if (sconn->smb1.echo_handler.trusted_fde) {
+ if (xconn->smb1.echo_handler.trusted_fde) {
DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
"'async smb echo handler = yes'\n"));
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
DEBUG(3,("reply_readbraw: fnum %d not valid "
"- cache prime?\n",
(int)SVAL(req->vwv+0, 0)));
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
(fsp->access_mask & FILE_EXECUTE)))) {
DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
(int)SVAL(req->vwv+0, 0)));
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
- flush_write_cache(fsp, READRAW_FLUSH);
+ flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
if(req->wct == 10) {
DEBUG(0,("reply_readbraw: negative 64 bit "
"readraw offset (%.0f) !\n",
(double)startpos ));
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_readbraw_error(sconn);
+ reply_readbraw_error(xconn);
END_PROFILE(SMBreadbraw);
return;
}
char *data;
off_t startpos;
size_t numtoread;
+ size_t maxtoread;
NTSTATUS status;
files_struct *fsp;
struct byte_range_lock *br_lck = NULL;
char *p = NULL;
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
START_PROFILE(SMBlockread);
numtoread = SVAL(req->vwv+1, 0);
startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
- numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
-
- reply_outbuf(req, 5, numtoread + 3);
-
- data = smb_buf(req->outbuf) + 3;
-
/*
* NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
* protocol request that predates the read/write lock concept.
* Thus instead of asking for a read lock here we need to ask
* for a write lock. JRA.
- * Note that the requested lock size is unaffected by max_recv.
+ * Note that the requested lock size is unaffected by max_send.
*/
br_lck = do_lock(req->sconn->msg_ctx,
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
- NULL,
NULL);
TALLOC_FREE(br_lck);
}
/*
- * However the requested READ size IS affected by max_recv. Insanity.... JRA.
+ * However the requested READ size IS affected by max_send. Insanity.... JRA.
*/
+ maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
- if (numtoread > sconn->smb1.negprot.max_recv) {
- DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
+ if (numtoread > maxtoread) {
+ DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
Returning short read of maximum allowed for compatibility with Windows 2000.\n",
- (unsigned int)numtoread,
- (unsigned int)sconn->smb1.negprot.max_recv));
- numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
+ (unsigned int)numtoread, (unsigned int)maxtoread,
+ (unsigned int)xconn->smb1.sessions.max_send));
+ numtoread = maxtoread;
}
+
+ reply_outbuf(req, 5, numtoread + 3);
+
+ data = smb_buf(req->outbuf) + 3;
+
nread = read_file(fsp,data,startpos,numtoread);
if (nread < 0) {
{
connection_struct *conn = req->conn;
size_t numtoread;
+ size_t maxtoread;
ssize_t nread = 0;
char *data;
off_t startpos;
- int outsize = 0;
files_struct *fsp;
struct lock_struct lock;
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
START_PROFILE(SMBread);
numtoread = SVAL(req->vwv+1, 0);
startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
-
/*
- * The requested read size cannot be greater than max_recv. JRA.
+ * The requested read size cannot be greater than max_send. JRA.
*/
- if (numtoread > sconn->smb1.negprot.max_recv) {
- DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
+ maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
+
+ if (numtoread > maxtoread) {
+ DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
Returning short read of maximum allowed for compatibility with Windows 2000.\n",
- (unsigned int)numtoread,
- (unsigned int)sconn->smb1.negprot.max_recv));
- numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
+ (unsigned int)numtoread, (unsigned int)maxtoread,
+ (unsigned int)xconn->smb1.sessions.max_send));
+ numtoread = maxtoread;
}
reply_outbuf(req, 5, numtoread+3);
files_struct *fsp, off_t startpos,
size_t smb_maxcnt)
{
+ struct smbXsrv_connection *xconn = req->xconn;
ssize_t nread = -1;
struct lock_struct lock;
int saved_errno = 0;
- if(fsp_stat(fsp) == -1) {
- reply_nterror(req, map_nt_error_from_unix(errno));
- return;
- }
-
init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
(uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
&lock);
return;
}
- if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
- (startpos > fsp->fsp_name->st.st_ex_size)
- || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
- /*
- * We already know that we would do a short read, so don't
- * try the sendfile() path.
- */
- goto nosendfile_read;
- }
-
/*
* We can only use sendfile on a non-chained packet
* but we can use on a non-oplocked file. tridge proved this
*/
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) ) {
+ lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
uint8 headerbuf[smb_size + 12 * 2];
DATA_BLOB header;
+ if(fsp_stat(fsp) == -1) {
+ reply_nterror(req, map_nt_error_from_unix(errno));
+ goto strict_unlock;
+ }
+
+ if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
+ (startpos > fsp->fsp_name->st.st_ex_size) ||
+ (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
+ /*
+ * We already know that we would do a short read, so don't
+ * try the sendfile() path.
+ */
+ goto nosendfile_read;
+ }
+
/*
* Set up the packet header before send. We
* assume here the sendfile will work (get the
construct_reply_common_req(req, (char *)headerbuf);
setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
- nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
+ nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
startpos, smb_maxcnt);
if (nread == -1) {
+ saved_errno = errno;
+
/* Returning ENOSYS means no data at all was sent.
Do this as a normal read. */
if (errno == ENOSYS) {
/* Ensure we don't do this again. */
set_use_sendfile(SNUM(conn), False);
DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
- nread = fake_sendfile(fsp, startpos,
+ nread = fake_sendfile(xconn, fsp, startpos,
smb_maxcnt);
if (nread == -1) {
+ saved_errno = errno;
DEBUG(0,("send_file_readX: "
"fake_sendfile failed for "
- "file %s (%s).\n",
+ "file %s (%s) for client %s. "
+ "Terminating\n",
fsp_str_dbg(fsp),
- strerror(errno)));
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
exit_server_cleanly("send_file_readX: fake_sendfile failed");
}
DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
/* Deal with possible short send. */
if (nread != smb_maxcnt + sizeof(headerbuf)) {
- sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
+ ssize_t ret;
+
+ ret = sendfile_short_send(xconn, fsp, nread,
+ sizeof(headerbuf), smb_maxcnt);
+ if (ret == -1) {
+ const char *r;
+ r = "send_file_readX: sendfile_short_send failed";
+ DEBUG(0,("%s for file %s (%s).\n",
+ r, fsp_str_dbg(fsp), strerror(errno)));
+ exit_server_cleanly(r);
+ }
}
/* No outbuf here means successful sendfile. */
SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
if ((smb_maxcnt & 0xFF0000) > 0x10000) {
uint8 headerbuf[smb_size + 2*12];
+ ssize_t ret;
construct_reply_common_req(req, (char *)headerbuf);
setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
/* Send out the header. */
- if (write_data(req->sconn->sock, (char *)headerbuf,
- sizeof(headerbuf)) != sizeof(headerbuf)) {
-
- char addr[INET6_ADDRSTRLEN];
+ ret = write_data(xconn->transport.sock, (char *)headerbuf,
+ sizeof(headerbuf));
+ if (ret != sizeof(headerbuf)) {
+ saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
- DEBUG(0, ("write_data failed for client %s. "
- "Error %s\n",
- get_peer_addr(req->sconn->sock, addr,
- sizeof(addr)),
- strerror(errno)));
-
DEBUG(0,("send_file_readX: write_data failed for file "
- "%s (%s). Terminating\n", fsp_str_dbg(fsp),
- strerror(errno)));
+ "%s (%s) for client %s. Terminating\n",
+ fsp_str_dbg(fsp),
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
exit_server_cleanly("send_file_readX sendfile failed");
}
- nread = fake_sendfile(fsp, startpos, smb_maxcnt);
+ nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
if (nread == -1) {
- DEBUG(0,("send_file_readX: fake_sendfile failed for "
- "file %s (%s).\n", fsp_str_dbg(fsp),
- strerror(errno)));
+ saved_errno = errno;
+ DEBUG(0,("send_file_readX: fake_sendfile failed for file "
+ "%s (%s) for client %s. Terminating\n",
+ fsp_str_dbg(fsp),
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
exit_server_cleanly("send_file_readX: fake_sendfile failed");
}
goto strict_unlock;
return;
}
+/****************************************************************************
+ Work out how much space we have for a read return.
+****************************************************************************/
+
+static size_t calc_max_read_pdu(const struct smb_request *req)
+{
+ struct smbXsrv_connection *xconn = req->xconn;
+
+ if (xconn->protocol < PROTOCOL_NT1) {
+ return xconn->smb1.sessions.max_send;
+ }
+
+ if (!lp_large_readwrite()) {
+ return xconn->smb1.sessions.max_send;
+ }
+
+ if (req_is_in_chain(req)) {
+ return xconn->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 xconn->smb1.sessions.max_send;
+ }
+
+ if (srv_is_signing_active(xconn)) {
+ 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)
+{
+ struct smbXsrv_connection *xconn = req->xconn;
+ 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 (xconn->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) {
/* NT_STATUS_RETRY - fall back to sync read. */
}
- smbd_lock_socket(req->sconn);
+ smbd_lock_socket(req->xconn);
send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
- smbd_unlock_socket(req->sconn);
+ smbd_unlock_socket(req->xconn);
out:
END_PROFILE(SMBreadX);
void reply_writebraw(struct smb_request *req)
{
connection_struct *conn = req->conn;
+ struct smbXsrv_connection *xconn = req->xconn;
char *buf = NULL;
ssize_t nwritten=0;
ssize_t total_written=0;
*/
SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
- if (srv_is_signing_active(req->sconn)) {
+ if (srv_is_signing_active(xconn)) {
END_PROFILE(SMBwritebraw);
exit_server_cleanly("reply_writebraw: SMB signing is active - "
"raw reads/writes are disallowed.");
return;
}
- if (req->sconn->smb1.echo_handler.trusted_fde) {
+ if (xconn->smb1.echo_handler.trusted_fde) {
DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
"'async smb echo handler = yes'\n"));
reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
}
/* Now read the raw data into the buffer and write it */
- status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
+ status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
&numtowrite);
if (!NT_STATUS_IS_OK(status)) {
exit_server_cleanly("secondary writebraw failed");
(int)tcount,(int)nwritten,(int)numtowrite));
}
- status = read_data(req->sconn->sock, buf+4, numtowrite);
+ status = read_data(xconn->transport.sock, buf+4, numtowrite);
if (!NT_STATUS_IS_OK(status)) {
- char addr[INET6_ADDRSTRLEN];
/* Try and give an error message
* saying what client failed. */
DEBUG(0, ("reply_writebraw: Oversize secondary write "
"raw read failed (%s) for client %s. "
"Terminating\n", nt_errstr(status),
- get_peer_addr(req->sconn->sock, addr,
- sizeof(addr))));
+ smbXsrv_connection_dbg(xconn)));
exit_server_cleanly("secondary writebraw failed");
}
* sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
* JRA.
*/
- if (!send_keepalive(req->sconn->sock)) {
+ if (!send_keepalive(xconn->transport.sock)) {
exit_server_cleanly("reply_writebraw: send of "
"keepalive failed");
}
(2*14) + /* word count (including bcc) */ \
1 /* pad byte */)
-bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
+bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
const uint8_t *inbuf)
{
size_t numtowrite;
- connection_struct *conn = NULL;
unsigned int doff = 0;
size_t len = smb_len_large(inbuf);
- struct smbXsrv_tcon *tcon;
+ uint16_t fnum;
+ struct smbXsrv_open *op = NULL;
+ struct files_struct *fsp = NULL;
NTSTATUS status;
- NTTIME now = 0;
- if (is_encrypted_packet(sconn, inbuf)) {
+ if (is_encrypted_packet(inbuf)) {
/* Can't do this on encrypted
* connections. */
return false;
return false;
}
- status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
- now, &tcon);
+ fnum = SVAL(inbuf, smb_vwv2);
+ status = smb1srv_open_lookup(xconn,
+ fnum,
+ 0, /* now */
+ &op);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
+ DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
+ return false;
+ }
+ fsp = op->compat;
+ if (fsp == NULL) {
+ DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
+ return false;
+ }
+ if (fsp->conn == NULL) {
+ DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
return false;
}
- conn = tcon->compat;
- if (IS_IPC(conn)) {
+ if (IS_IPC(fsp->conn)) {
DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
return false;
}
- if (IS_PRINT(conn)) {
+ if (IS_PRINT(fsp->conn)) {
DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
return false;
}
void reply_write_and_X(struct smb_request *req)
{
connection_struct *conn = req->conn;
+ struct smbXsrv_connection *xconn = req->xconn;
files_struct *fsp;
struct lock_struct lock;
off_t startpos;
out:
if (req->unread_bytes) {
/* writeX failed. drain socket. */
- if (drain_socket(req->sconn->sock, req->unread_bytes) !=
+ if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
req->unread_bytes) {
smb_panic("failed to drain pending bytes");
}
return;
}
- flush_write_cache(fsp, SEEK_FLUSH);
+ flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
mode = SVAL(req->vwv+1, 0) & 3;
/* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
return;
}
-/****************************************************************************
- Reply to a close - has to deal with closing a directory opened by NT SMB's.
-****************************************************************************/
+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)
{
return;
}
- if(fsp->is_directory) {
- /*
- * Special case - close NT SMB directory handle.
- */
- DEBUG(3,("close directory %s\n", fsp_fnum_dbg(fsp)));
- status = close_file(req, fsp, NORMAL_CLOSE);
- } else {
- time_t t;
- /*
- * Close ordinary file.
- */
+ DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
+ fsp->is_directory ? "directory" : "file",
+ fsp->fh->fd, fsp_fnum_dbg(fsp),
+ conn->num_files_open));
- DEBUG(3,("close fd=%d %s (numopen=%d)\n",
- fsp->fh->fd, fsp_fnum_dbg(fsp),
- conn->num_files_open));
+ if (!fsp->is_directory) {
+ time_t t;
/*
* Take care of any time sent in the close.
t = srv_make_unix_date3(req->vwv+1);
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));
/*
- * 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 was probably an I/O error.
+ * We depend on the aio_extra destructor to take care of this
+ * close request once fsp->num_aio_request drops to 0.
*/
- status = close_file(req, fsp, NORMAL_CLOSE);
- }
+ 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
+ * was probably an I/O error.
+ */
+
+ 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).
****************************************************************************/
mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
data = (const char *)req->buf + 1;
- if (!fsp->print_file) {
+ if (fsp->print_file == NULL) {
init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
(uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
&lock);
nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ if (fsp->print_file == NULL) {
+ SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
+ }
+
set_close_write_time(fsp, mtime);
/*
* JRA.
*/
+ DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
+ fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
+ (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
+
if (numtowrite) {
DEBUG(3,("reply_writeclose: zero length write doesn't close "
"file %s\n", fsp_str_dbg(fsp)));
close_status = close_file(req, fsp, NORMAL_CLOSE);
+ fsp = NULL;
}
- DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
- fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
- conn->num_files_open));
-
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
reply_nterror(req, NT_STATUS_DISK_FULL);
- goto strict_unlock;
+ goto out;
}
if(!NT_STATUS_IS_OK(close_status)) {
reply_nterror(req, close_status);
- goto strict_unlock;
+ goto out;
}
reply_outbuf(req, 1, 0);
SSVAL(req->outbuf,smb_vwv0,nwritten);
-strict_unlock:
- if (numtowrite && !fsp->print_file) {
- SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
- }
+out:
END_PROFILE(SMBwriteclose);
return;
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
- NULL,
NULL);
TALLOC_FREE(br_lck);
TALLOC_CTX *mem_ctx = talloc_tos();
NTSTATUS status;
WERROR werr;
- const char *sharename = lp_servicename(SNUM(conn));
+ const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
struct rpc_pipe_client *cli = NULL;
struct dcerpc_binding_handle *b = NULL;
struct policy_handle handle;
ZERO_STRUCT(handle);
status = rpc_pipe_open_interface(conn,
- &ndr_table_spoolss.syntax_id,
+ &ndr_table_spoolss,
conn->session_info,
conn->sconn->remote_address,
conn->sconn->msg_ctx,
status = filename_convert(ctx, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
directory,
- 0,
+ UCF_PREP_CREATEFILE,
NULL,
&smb_dname);
if (!NT_STATUS_IS_OK(status)) {
FILE_DIRECTORY_FILE, /* create_options */
FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
0, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
static void rename_open_files(connection_struct *conn,
struct share_mode_lock *lck,
+ struct file_id id,
uint32_t orig_name_hash,
const struct smb_filename *smb_fname_dst)
{
NTSTATUS status;
uint32_t new_name_hash = 0;
- for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
+ for(fsp = file_find_di_first(conn->sconn, id); fsp;
fsp = file_find_di_next(fsp)) {
/* fsp_name is a relative path under the fsp. To change this for other
sharepaths we need to manipulate relative paths. */
if (!did_rename) {
DEBUG(10, ("rename_open_files: no open files on file_id %s "
- "for %s\n", file_id_string_tos(&lck->data->id),
+ "for %s\n", file_id_string_tos(&id),
smb_fname_str_dbg(smb_fname_dst)));
}
/* Send messages to all smbd's (not ourself) that the name has changed. */
- rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
+ rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
orig_name_hash, new_name_hash,
smb_fname_dst);
/* Make a copy of the dst smb_fname structs */
- status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
+ smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
+ if (smb_fname_dst == NULL) {
+ status = NT_STATUS_NO_MEMORY;
goto out;
}
* Create an smb_filename struct using the original last
* component of the destination.
*/
- status = create_synthetic_smb_fname_split(ctx,
- smb_fname_dst->original_lcomp, NULL,
- &smb_fname_orig_lcomp);
- if (!NT_STATUS_IS_OK(status)) {
+ smb_fname_orig_lcomp = synthetic_smb_fname_split(
+ ctx, smb_fname_dst->original_lcomp, NULL);
+ if (smb_fname_orig_lcomp == NULL) {
+ status = NT_STATUS_NO_MEMORY;
TALLOC_FREE(fname_dst_lcomp_base_mod);
goto out;
}
"%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
notify_rename(conn, fsp->is_directory, fsp->fsp_name,
smb_fname_dst);
- rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
+ rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
+ smb_fname_dst);
/*
* A rename acts as a new file create w.r.t. allowing an initial delete
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)) {
create_options, /* create_options */
posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
0, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
create_options, /* create_options */
posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
0, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NTSTATUS status;
- status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
+ if (smb_fname_dst_tmp == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
/*
0, /* create_options */
FILE_ATTRIBUTE_NORMAL, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
0, /* create_options */
dosattrs, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
+ NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
if(!large_file_format) {
count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
} else {
-
-#if defined(HAVE_LONGLONG)
- count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
- ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
-#else /* HAVE_LONGLONG */
-
/*
- * NT4.x seems to be broken in that it sends large file (64 bit)
- * lockingX calls even if the CAP_LARGE_FILES was *not*
- * negotiated. For boxes without large unsigned ints truncate the
- * lock count by dropping the top 32 bits.
+ * No BVAL, this is reversed!
*/
-
- if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
- DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
- (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
- (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
- SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
- }
-
- count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
-#endif /* HAVE_LONGLONG */
+ count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+ ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
}
return count;
}
-#if !defined(HAVE_LONGLONG)
-/****************************************************************************
- Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
-****************************************************************************/
-
-static uint32 map_lock_offset(uint32 high, uint32 low)
-{
- unsigned int i;
- uint32 mask = 0;
- uint32 highcopy = high;
-
- /*
- * Try and find out how many significant bits there are in high.
- */
-
- for(i = 0; highcopy; i++)
- highcopy >>= 1;
-
- /*
- * We use 31 bits not 32 here as POSIX
- * lock offsets may not be negative.
- */
-
- mask = (~0) << (31 - i);
-
- if(low & mask)
- return 0; /* Fail. */
-
- high <<= (31 - i);
-
- return (high|low);
-}
-#endif /* !defined(HAVE_LONGLONG) */
-
/****************************************************************************
Get a lock offset, dealing with large offset requests.
****************************************************************************/
uint64_t get_lock_offset(const uint8_t *data, int data_offset,
- bool large_file_format, bool *err)
+ bool large_file_format)
{
uint64_t offset = 0;
- *err = False;
-
if(!large_file_format) {
offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
} else {
-
-#if defined(HAVE_LONGLONG)
- offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
- ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
-#else /* HAVE_LONGLONG */
-
/*
- * NT4.x seems to be broken in that it sends large file (64 bit)
- * lockingX calls even if the CAP_LARGE_FILES was *not*
- * negotiated. For boxes without large unsigned ints mangle the
- * lock offset by mapping the top 32 bits onto the lower 32.
+ * No BVAL, this is reversed!
*/
-
- if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
- uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
- uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
- uint32 new_low = 0;
-
- if((new_low = map_lock_offset(high, low)) == 0) {
- *err = True;
- return (uint64_t)-1;
- }
-
- DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
- (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
- SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
- SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
- }
-
- offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
-#endif /* HAVE_LONGLONG */
+ offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+ ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
}
return offset;
files_struct *fsp,
uint8_t type,
int32_t timeout,
- uint16_t num_ulocks,
- struct smbd_lock_element *ulocks,
uint16_t num_locks,
struct smbd_lock_element *locks,
bool *async)
*async = false;
- /* Data now points at the beginning of the list
- of smb_unlkrng structs */
- for(i = 0; i < (int)num_ulocks; i++) {
- struct smbd_lock_element *e = &ulocks[i];
-
- DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
- "pid %u, file %s\n",
- (double)e->offset,
- (double)e->count,
- (unsigned int)e->smblctx,
- fsp_str_dbg(fsp)));
-
- if (e->brltype != UNLOCK_LOCK) {
- /* this can only happen with SMB2 */
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- status = do_unlock(req->sconn->msg_ctx,
- fsp,
- e->smblctx,
- e->count,
- e->offset,
- WINDOWS_LOCK);
-
- DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
- nt_errstr(status)));
-
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
/* Setup the timeout in seconds. */
if (!lp_blocking_locks(SNUM(conn))) {
timeout = 0;
}
- /* Data now points at the beginning of the list
- of smb_lkrng structs */
-
for(i = 0; i < (int)num_locks; i++) {
struct smbd_lock_element *e = &locks[i];
if (num_locks > 1) {
/*
* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
- * if the lock vector contains one entry. When given mutliple cancel
+ * if the lock vector contains one entry. When given multiple cancel
* requests in a single PDU we expect the server to return an
* error. Windows servers seem to accept the request but only
* cancel the first lock.
e->smblctx,
e->count,
e->offset,
- WINDOWS_LOCK,
- blr);
+ WINDOWS_LOCK);
} else {
bool blocking_lock = timeout ? true : false;
bool defer_lock = false;
WINDOWS_LOCK,
blocking_lock,
&status,
- &block_smblctx,
- NULL);
+ &block_smblctx);
if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
/* Windows internal resolution for blocking locks seems
return status;
}
- DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
- fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
+ DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
+ fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbd_do_unlocking(struct smb_request *req,
+ files_struct *fsp,
+ uint16_t num_ulocks,
+ struct smbd_lock_element *ulocks)
+{
+ int i;
+
+ for(i = 0; i < (int)num_ulocks; i++) {
+ struct smbd_lock_element *e = &ulocks[i];
+ NTSTATUS status;
+
+ DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
+ "pid %u, file %s\n", __func__,
+ (double)e->offset,
+ (double)e->count,
+ (unsigned int)e->smblctx,
+ fsp_str_dbg(fsp)));
+
+ if (e->brltype != UNLOCK_LOCK) {
+ /* this can only happen with SMB2 */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = do_unlock(req->sconn->msg_ctx,
+ fsp,
+ e->smblctx,
+ e->count,
+ e->offset,
+ WINDOWS_LOCK);
+
+ DEBUG(10, ("%s: unlock returned %s\n", __func__,
+ nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
+ num_ulocks));
return NT_STATUS_OK;
}
int i;
const uint8_t *data;
bool large_file_format;
- bool err;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
struct smbd_lock_element *ulocks;
struct smbd_lock_element *locks;
num_ulocks = SVAL(req->vwv+6, 0);
num_locks = SVAL(req->vwv+7, 0);
lock_timeout = IVAL(req->vwv+4, 0);
- large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+ large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
if (!check_fsp(conn, req, fsp)) {
END_PROFILE(SMBlockingX);
/* Check if this is an oplock break on a file
we have granted an oplock on.
*/
- if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
+ if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
/* Client can insist on breaking to none. */
bool break_to_none = (oplocklevel == 0);
bool result;
smb_panic("internal tdb error");
}
- reply_to_oplock_break_requests(fsp);
-
/* if this is a pure oplock break request then don't send a
* reply */
if (num_locks == 0 && num_ulocks == 0) {
/* Sanity check - ensure a pure oplock break is not a
chained request. */
- if(CVAL(req->vwv+0, 0) != 0xff)
+ if (CVAL(req->vwv+0, 0) != 0xff) {
DEBUG(0,("reply_lockingX: Error : pure oplock "
"break is a chained %d request !\n",
(unsigned int)CVAL(req->vwv+0, 0)));
+ }
END_PROFILE(SMBlockingX);
return;
}
for(i = 0; i < (int)num_ulocks; i++) {
ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
ulocks[i].count = get_lock_count(data, i, large_file_format);
- ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
+ ulocks[i].offset = get_lock_offset(data, i, large_file_format);
ulocks[i].brltype = UNLOCK_LOCK;
-
- /*
- * There is no error code marked "stupid client bug".... :-).
- */
- if(err) {
- reply_nterror(req, NT_STATUS_ACCESS_DENIED);
- END_PROFILE(SMBlockingX);
- return;
- }
}
/* Now do any requested locks */
for(i = 0; i < (int)num_locks; i++) {
locks[i].smblctx = get_lock_pid(data, i, large_file_format);
locks[i].count = get_lock_count(data, i, large_file_format);
- locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
+ locks[i].offset = get_lock_offset(data, i, large_file_format);
if (locktype & LOCKING_ANDX_SHARED_LOCK) {
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
locks[i].brltype = WRITE_LOCK;
}
}
+ }
- /*
- * There is no error code marked "stupid client bug".... :-).
- */
- if(err) {
- reply_nterror(req, NT_STATUS_ACCESS_DENIED);
- END_PROFILE(SMBlockingX);
- return;
- }
+ status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBlockingX);
+ reply_nterror(req, status);
+ return;
}
status = smbd_do_locking(req, fsp,
locktype, lock_timeout,
- num_ulocks, ulocks,
num_locks, locks,
&async);
if (!NT_STATUS_IS_OK(status)) {