#include "../lib/util/tevent_ntstatus.h"
#include "messages.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SMB2
+
int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
{
switch(in_oplock_level) {
}
}
+/*
+ MS-FSA 2.1.5.1 Server Requests an Open of a File
+ Trailing '/' or '\\' checker.
+ Must be done before the filename parser removes any
+ trailing characters. If we decide to add this to SMB1
+ NTCreate processing we can make this public.
+
+ Note this is Windows pathname processing only. When
+ POSIX pathnames are added to SMB2 this will not apply.
+*/
+
+static NTSTATUS windows_name_trailing_check(const char *name,
+ uint32_t create_options)
+{
+ size_t name_len = strlen(name);
+ char trail_c;
+
+ if (name_len <= 1) {
+ return NT_STATUS_OK;
+ }
+
+ trail_c = name[name_len-1];
+
+ /*
+ * Trailing '/' is always invalid.
+ */
+ if (trail_c == '/') {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ if (trail_c == '\\') {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_smb2_request *smb2req,
SCVAL(outbody.data, 0x03, 0); /* reserved */
SIVAL(outbody.data, 0x04,
out_create_action); /* create action */
- put_long_date_timespec(conn->ts_res,
+ put_long_date_full_timespec(conn->ts_res,
(char *)outbody.data + 0x08,
- out_creation_ts); /* creation time */
- put_long_date_timespec(conn->ts_res,
+ &out_creation_ts); /* creation time */
+ put_long_date_full_timespec(conn->ts_res,
(char *)outbody.data + 0x10,
- out_last_access_ts); /* last access time */
- put_long_date_timespec(conn->ts_res,
+ &out_last_access_ts); /* last access time */
+ put_long_date_full_timespec(conn->ts_res,
(char *)outbody.data + 0x18,
- out_last_write_ts); /* last write time */
- put_long_date_timespec(conn->ts_res,
+ &out_last_write_ts); /* last write time */
+ put_long_date_full_timespec(conn->ts_res,
(char *)outbody.data + 0x20,
- out_change_ts); /* change time */
+ &out_change_ts); /* change time */
SBVAL(outbody.data, 0x28,
out_allocation_size); /* allocation size */
SBVAL(outbody.data, 0x30,
const char *requested_filename, const struct files_struct *fsp,
const struct smb2_lease *lease_ptr)
{
+ char *filename = NULL;
struct smb_filename *smb_fname = NULL;
uint32_t ucf_flags;
NTSTATUS status;
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
+ filename = talloc_strdup(talloc_tos(), requested_filename);
+ if (filename == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* This also converts '\' to '/' */
+ status = check_path_syntax(filename);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(filename);
+ return status;
+ }
+
ucf_flags = filename_create_ucf_flags(smb1req, FILE_OPEN);
status = filename_convert(talloc_tos(), fsp->conn,
- requested_filename, ucf_flags,
- NULL, &smb_fname);
+ filename, ucf_flags,
+ NULL, NULL, &smb_fname);
+ TALLOC_FREE(filename);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("filename_convert returned %s\n",
nt_errstr(status)));
ssize_t lease_len;
bool need_replay_cache;
struct smbXsrv_open *op;
+ time_t twrp_time;
+ time_t *twrp_timep;
struct smb2_create_blob *dhnc;
struct smb2_create_blob *dh2c;
struct smbd_smb2_create_state *state = tevent_req_data(
req, struct smbd_smb2_create_state);
+ /*
+ * For now, remove the posix create context from the wire. We
+ * are using it inside smbd and will properly use it once
+ * smb3.11 unix extensions will be done. So in the future we
+ * will remove it only if unix extensions are not negotiated.
+ */
+ smb2_create_blob_remove(in_context_blobs, SMB2_CREATE_TAG_POSIX);
+
state->dhnq = smb2_create_blob_find(in_context_blobs,
SMB2_CREATE_TAG_DHNQ);
state->dhnc = smb2_create_blob_find(in_context_blobs,
state->smb1req = smb1req;
if (smb2req->subreq == NULL) {
- DEBUG(10,("smbd_smb2_create: name[%s]\n",
- in_name));
+ DBG_DEBUG("name [%s]\n", in_name);
} else {
struct smbd_smb2_create_state *old_state = tevent_req_data(
smb2req->subreq, struct smbd_smb2_create_state);
- DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
- in_name ));
+ DBG_DEBUG("reentrant for file %s\n", in_name);
state->id = old_state->id;
state->request_time = old_state->request_time;
return req;
}
+ /* Check for trailing slash specific directory handling. */
+ status = windows_name_trailing_check(state->fname, in_create_options);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, state->ev);
+ }
+
smbd_smb2_create_before_exec(req);
if (!tevent_req_is_in_progress(req)) {
return tevent_req_post(req, state->ev);
}
- DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
+ DBG_DEBUG("open execution phase\n");
/*
* For the backend file open procedure, there are
now,
&state->op);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3, ("smbd_smb2_create_send: "
- "smb2srv_open_recreate failed: %s\n",
- nt_errstr(status)));
+ DBG_NOTICE("smb2srv_open_recreate failed: %s\n",
+ nt_errstr(status));
tevent_req_nterror(req, status);
return tevent_req_post(req, state->ev);
}
- DEBUG(10, ("smb2_create_send: %s to recreate the "
- "smb2srv_open struct for a durable handle.\n",
- state->op->global->durable ? "succeeded" : "failed"));
+ DBG_DEBUG("%s to recreate durable handle\n",
+ state->op->global->durable ? "succeeded" : "failed");
if (!state->op->global->durable) {
talloc_free(state->op);
return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- DEBUG(3, ("smbd_smb2_create_send: "
- "durable_reconnect failed: %s => %s\n",
- nt_errstr(status),
- nt_errstr(return_status)));
+ DBG_NOTICE("durable_reconnect failed: %s => %s\n",
+ nt_errstr(status),
+ nt_errstr(return_status));
tevent_req_nterror(req, return_status);
return tevent_req_post(req, state->ev);
}
- DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
- (unsigned)state->result->oplock_type, state->lease_ptr));
+ DBG_DEBUG("oplock_type=%u, lease_ptr==%p\n",
+ (unsigned)state->result->oplock_type, state->lease_ptr);
status = smbd_smb2_create_durable_lease_check(
smb1req, state->fname, state->result, state->lease_ptr);
smb1req->conn,
state->fname,
ucf_flags,
+ state->twrp_timep,
NULL, /* ppath_contains_wcards */
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (state->twrp != NULL) {
NTTIME nttime;
- time_t t;
- struct tm *tm;
- char *tmpname = state->fname;
if (state->twrp->data.length != 8) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
}
nttime = BVAL(state->twrp->data.data, 0);
- t = nt_time_to_unix(nttime);
- tm = gmtime(&t);
+ state->twrp_time = nt_time_to_unix(nttime);
+ state->twrp_timep = &state->twrp_time;
- state->fname = talloc_asprintf(
- state,
- "%s\\@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
- state->fname,
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- if (tevent_req_nomem(state->fname, req)) {
- return;
- }
- TALLOC_FREE(tmpname);
- /*
- * Tell filename_create_ucf_flags() this
- * is an @GMT path.
- */
smb1req->flags2 |= FLAGS2_REPARSE_PATH;
}
}
}
}
-
- return;
}
static void smbd_smb2_create_after_exec(struct tevent_req *req)
DEBUG(10, ("smbd_smb2_create_send: "
"response construction phase\n"));
+ state->out_file_attributes = dos_mode(state->result->conn,
+ state->result->fsp_name);
+
if (state->mxac != NULL) {
NTTIME last_write_time;
- last_write_time = unix_timespec_to_nt_time(
- state->result->fsp_name->st.st_ex_mtime);
+ last_write_time = full_timespec_to_nt_time(
+ &state->result->fsp_name->st.st_ex_mtime);
if (last_write_time != state->max_access_time) {
uint8_t p[8];
uint32_t max_access_granted;
DATA_BLOB blob = data_blob_const(p, sizeof(p));
status = smbd_calculate_access_mask(smb1req->conn,
- state->result->fsp_name,
- false,
- SEC_FLAG_MAXIMUM_ALLOWED,
- &max_access_granted);
+ smb1req->conn->cwd_fsp,
+ state->result->fsp_name,
+ false,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &max_access_granted);
SIVAL(p, 0, NT_STATUS_V(status));
SIVAL(p, 4, max_access_granted);
if (state->qfid != NULL) {
uint8_t p[32];
- uint64_t file_index = get_FileIndex(state->result->conn,
- &state->result->fsp_name->st);
+ uint64_t file_id = SMB_VFS_FS_FILE_ID(
+ state->result->conn,
+ &state->result->fsp_name->st);
DATA_BLOB blob = data_blob_const(p, sizeof(p));
ZERO_STRUCT(p);
the MS plugfest. The first 8 bytes are the "volume index"
== inode, the second 8 bytes are the "volume id",
== dev. This will be updated in the SMB2 doc. */
- SBVAL(p, 0, file_index);
+ SBVAL(p, 0, file_id);
SIVAL(p, 8, state->result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
status = smb2_create_blob_add(state->out_context_blobs,
state->out_create_action = state->info;
}
result->op->create_action = state->out_create_action;
- state->out_file_attributes = dos_mode(result->conn,
- result->fsp_name);
state->out_creation_ts = get_create_timespec(smb1req->conn,
result, result->fsp_name);
tevent_req_done(req);
tevent_req_post(req, state->ev);
- return;
}
static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,