#include "../librpc/gen_ndr/ndr_security.h"
#include "../lib/util/tevent_ntstatus.h"
#include "messages.h"
+#include "librpc/gen_ndr/open_files.h"
+#include "serverid.h"
int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
{
}
}
+/*
+ * TODO: needs to be moved - copied from source3/smbd/files.c
+ */
+static unsigned long get_gen_count(struct smbd_server_connection *sconn)
+{
+ sconn->file_gen_counter += 1;
+ if (sconn->file_gen_counter == 0) {
+ sconn->file_gen_counter += 1;
+ }
+
+ return sconn->file_gen_counter;
+}
+
+static NTSTATUS new_durable_reconnect_fsp(struct smbXsrv_open *op,
+ struct connection_struct *conn,
+ struct smb_filename *smb_fname,
+ TALLOC_CTX *mem_ctx,
+ files_struct **_fsp)
+{
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ files_struct *fsp = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct smbd_server_connection *sconn = op->connection->sconn;
+
+ fsp = talloc_zero(frame, struct files_struct);
+ if (fsp == NULL) {
+ goto fail;
+ }
+
+ /*
+ * This can't be a child of fsp because the file_handle can be ref'd
+ * when doing a dos/fcb open, which will then share the file_handle
+ * across multiple fsps.
+ */
+ fsp->fh = talloc_zero(frame, struct fd_handle);
+ if (fsp->fh == NULL) {
+ goto fail;
+ }
+
+ status = fsp_set_smb_fname(fsp, smb_fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ fsp->fh->ref_count = 1;
+ fsp->fh->fd = -1;
+ fsp->fh->gen_id = get_gen_count(sconn);
+
+ fsp->conn = conn;
+
+
+ /* success */
+
+ talloc_steal(mem_ctx, fsp);
+ talloc_steal(mem_ctx, fsp->fh);
+ *_fsp = fsp;
+
+ status = NT_STATUS_OK;
+
+fail:
+ talloc_free(frame);
+ return status;
+}
+
+static NTSTATUS smb2_create_durable_reconnect(struct smbXsrv_open *op,
+ /* struct smb_request *smb1req, */
+ struct connection_struct *conn,
+ struct smb_filename *smb_fname,
+ TALLOC_CTX *mem_ctx,
+ files_struct **_fsp)
+{
+ struct share_mode_lock *sharemode_lock;
+ files_struct *fsp = NULL;
+ NTSTATUS status;
+
+DEBUG(0, ("OBNOX - durable_reconnect enter: (%s:%s)\n", __location__, __FUNCTION__));
+
+ /* 1. check entry in locking.tdb */
+
+ /*
+ * Q: fetch with lock right away?
+ */
+/*
+ sharemode_lock = fetch_share_mode_unlocked(mem_ctx,
+ op->global->backend_file_id);
+*/
+ sharemode_lock = get_share_mode_lock(mem_ctx,
+ op->global->backend_file_id);
+ if (sharemode_lock == NULL) {
+ /* TODO: use/create other fetch func with better error code */
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (sharemode_lock->data->num_share_modes == 0) {
+ /* should not happen? internal error? */
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ if (sharemode_lock->data->num_share_modes > 1) {
+ /*
+ * It can't be durable if there is more than one handle
+ * on the file.
+ */
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (serverid_exists(&sharemode_lock->data->share_modes[0].pid)) {
+ /*
+ * server still exists
+ * TODO: check whether session exists
+ * (could have been a session_logoff())
+ */
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* 2. proceed with opening file */
+
+ /*
+ * refetch with lock and update the pid // fetch with lock right away above
+ */
+/*
+ talloc_free(sharemode_lock);
+ sharemode_lock = get_share_mode_lock(mem_ctx,
+ op->global->backend_file_id);
+ if (sharemode_lock == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+*/
+
+ sharemode_lock->data->share_modes[0].pid =
+ messaging_server_id(op->connection->sconn->msg_ctx);
+
+ /*
+ * circumstances seems ok, do the open
+ */
+ status = new_durable_reconnect_fsp(op, conn, smb_fname, mem_ctx, &fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+DEBUG(0, ("OBNOX - durable_reconnect: new fsp created (%s:%s)\n", __location__, __FUNCTION__));
+
+ fsp->fh->fd = SMB_VFS_OPEN(conn,
+ smb_fname,
+ fsp,
+ sharemode_lock->data->share_modes[0].flags,
+ 0 /* mode */);
+ if (fsp->fh->fd == -1) {
+ /* ... */
+ return NT_STATUS_UNSUCCESSFUL; // TODO ERROR CODE?
+ }
+
+ /* - release the sharemode lock: this writes the changes */
+ talloc_free(sharemode_lock);
+
+
+ /* Q: do this in fsp creation? */
+ op->fsp = fsp;
+ *_fsp = fsp;
+
+ /*
+ * - return
+ *
+ * ... think about seek()
+ */
+ return NT_STATUS_OK;
+}
+
struct smbd_smb2_create_state {
struct smbd_smb2_request *smb2req;
struct smb_request *smb1req;
struct timespec write_time_ts;
struct smb2_create_blobs out_context_blobs;
int requested_oplock_level;
+ bool do_durable_reconnect = false;
+ struct smbXsrv_open *op = NULL;
ZERO_STRUCT(out_context_blobs);
}
if (dhnc) {
+ uint64_t persistent_id;
+
+DEBUG(0, ("OBNOX - dhnc found (%s:%s)\n", __location__, __FUNCTION__));
+
if (dhnc->data.length != 16) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
- /* we don't support durable handles yet */
- tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
- return tevent_req_post(req, ev);
+
+ persistent_id = BVAL(dhnc->data.data, 0);
+
+ status = smb2srv_open_recreate(smb2req->sconn->conn,
+ persistent_id,
+ &op);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ /* TODO: needed? or is successful global_lookup enough?) */
+
+ if (!op->global->durable) {
+ talloc_free(op);
+ tevent_req_nterror(req,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ return tevent_req_post(req, ev);
+ }
+
+ do_durable_reconnect = true;
}
if (alsi) {
smb1req->conn,
smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
- 0,
- NULL,
+ 0, /* unix_convert flags */
+ NULL, /* ppath_contains_wcards */
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
/*
- * TODO:
- * implement retrieval of persistent file id
- * inside SMB_VFS_CREATE_FILE (for now)
- * or separate further down?
- *
+ * For the backend file open procedure, there are
+ * two possible modes: durable_reconnect or not.
*/
- status = SMB_VFS_CREATE_FILE(smb1req->conn,
- smb1req,
- 0, /* root_dir_fid */
- smb_fname,
- in_desired_access,
- in_share_access,
- in_create_disposition,
- in_create_options,
- in_file_attributes,
- map_smb2_oplock_levels_to_samba(requested_oplock_level),
- allocation_size,
- 0, /* private_flags */
- sec_desc,
- ea_list,
- &result,
- &info);
- if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(smb1req->sconn, smb1req->mid)) {
- return req;
+ if (do_durable_reconnect) {
+ status = smb2_create_durable_reconnect(op,
+ smb1req->conn,
+ smb_fname,
+ mem_ctx,
+ &result);
+
+DEBUG(0, ("OBNOX - durable_reconnect result: %s (%s:%s)\n", nt_errstr(status), __location__, __FUNCTION__));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ status = SMB_VFS_CREATE_FILE(smb1req->conn,
+ smb1req,
+ 0, /* root_dir_fid */
+ smb_fname,
+ in_desired_access,
+ in_share_access,
+ in_create_disposition,
+ in_create_options,
+ in_file_attributes,
+ map_smb2_oplock_levels_to_samba(requested_oplock_level),
+ allocation_size,
+ 0, /* private_flags */
+ sec_desc,
+ ea_list,
+ &result,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(smb1req->sconn, smb1req->mid)) {
+ return req;
+ }
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
}
- tevent_req_nterror(req, status);
- return tevent_req_post(req, ev);
}
if (mxac) {
}
}
- if (dhnq && BATCH_OPLOCK_TYPE(result->oplock_type)) {
+ /*
+ * windows createst a dhnc response blob upon dbnc request.
+ * this seems to contradict the documentation, though
+ * --> TODO:dochelp
+ */
+ if (dhnc || (dhnq && BATCH_OPLOCK_TYPE(result->oplock_type))) {
uint8_t p[8];
DATA_BLOB blob = data_blob_const(p, sizeof(p));
+ result->smbXsrv->global->backend_file_id = result->file_id;
+ result->smbXsrv->global->durable = true;
+
+ status = smbXsrv_open_update(result->smbXsrv);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
ZERO_STRUCT(p);
status = smb2_create_blob_add(state, &out_context_blobs,
if (state->out_file_attributes == 0) {
state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
}
- /*
- * TODO:
- * in case of durable open, persistent id must be
- * generated from a db, being unique server-wide.
- */
- state->out_file_id_persistent = result->fnum;
- state->out_file_id_volatile = result->fnum;
+
+ state->out_file_id_persistent = result->smbXsrv->global->open_persistent_id;
+ state->out_file_id_volatile = result->smbXsrv->global->open_volatile_id;
state->out_context_blobs = out_context_blobs;
tevent_req_done(req);