コード例 #1
0
ファイル: files.c プロジェクト: sprymak/samba
NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from,
		      uint32 access_mask, uint32 share_access,
		      uint32 create_options, files_struct *to)
{
	TALLOC_FREE(to->fh);

	to->fh = from->fh;
	to->fh->ref_count++;

	to->file_id = from->file_id;
	to->initial_allocation_size = from->initial_allocation_size;
	to->file_pid = from->file_pid;
	to->vuid = from->vuid;
	to->open_time = from->open_time;
	to->access_mask = access_mask;
	to->share_access = share_access;
	to->oplock_type = from->oplock_type;
	to->can_lock = from->can_lock;
	to->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
	if (!CAN_WRITE(from->conn)) {
		to->can_write = False;
	} else {
		to->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;
	}
	to->modified = from->modified;
	to->is_directory = from->is_directory;
	to->aio_write_behind = from->aio_write_behind;

	if (from->print_file) {
		to->print_file = talloc(to, struct print_file_data);
		if (!to->print_file) return NT_STATUS_NO_MEMORY;
		to->print_file->rap_jobid = from->print_file->rap_jobid;
	} else {
コード例 #2
0
NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from,
		      uint32 access_mask, uint32 share_access,
		      uint32 create_options, files_struct *to)
{
	/* this can never happen for print files */
	SMB_ASSERT(from->print_file == NULL);

	TALLOC_FREE(to->fh);

	to->fh = from->fh;
	to->fh->ref_count++;

	to->file_id = from->file_id;
	to->initial_allocation_size = from->initial_allocation_size;
	to->file_pid = from->file_pid;
	to->vuid = from->vuid;
	to->open_time = from->open_time;
	to->access_mask = access_mask;
	to->share_access = share_access;
	to->oplock_type = from->oplock_type;
	to->can_lock = from->can_lock;
	to->can_read = ((access_mask & FILE_READ_DATA) != 0);
	to->can_write =
		CAN_WRITE(from->conn) &&
		((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
	to->modified = from->modified;
	to->is_directory = from->is_directory;
	to->aio_write_behind = from->aio_write_behind;

	return fsp_set_smb_fname(to, from->fsp_name);
}
コード例 #3
0
ファイル: dosmode.c プロジェクト: abartlet/samba-old
int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
		struct smb_file_time *ft)
{
	int ret = -1;

	errno = 0;

	DEBUG(6, ("file_ntime: actime: %s",
		  time_to_asc(convert_timespec_to_time_t(ft->atime))));
	DEBUG(6, ("file_ntime: modtime: %s",
		  time_to_asc(convert_timespec_to_time_t(ft->mtime))));
	DEBUG(6, ("file_ntime: ctime: %s",
		  time_to_asc(convert_timespec_to_time_t(ft->ctime))));
	DEBUG(6, ("file_ntime: createtime: %s",
		  time_to_asc(convert_timespec_to_time_t(ft->create_time))));

	/* Don't update the time on read-only shares */
	/* We need this as set_filetime (which can be called on
	   close and other paths) can end up calling this function
	   without the NEED_WRITE protection. Found by : 
	   Leo Weppelman <*****@*****.**>
	*/

	if (!CAN_WRITE(conn)) {
		return 0;
	}

	if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES)) {
		return -1;
	}

	if(!lp_dos_filetimes(SNUM(conn))) {
		return -1;
	}

	/* We have permission (given by the Samba admin) to
	   break POSIX semantics and allow a user to change
	   the time on a file they don't own but can write to
	   (as DOS does).
	 */

	/* Check if we have write access. */
	if (can_write_to_file(conn, smb_fname)) {
		/* We are allowed to become root and change the filetime. */
		become_root();
		ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
		unbecome_root();
	}

	return ret;
}
コード例 #4
0
ファイル: apdb.c プロジェクト: guoyu07/jff
apdb_record_t
apdb_add_end(apdb_t* db, const void* content)
{
    index_t index, *indexp;
    int content_len;

    assert(NULL != db && ADD == db->action && CAN_WRITE(db) &&
           db->next_length == db->next_written);
    assert(db->index_file_len <= db->index_mmap_len);

    db->action = NONE;

    if (db->error)
        return -1;

    ERROR_IF(db->next_length != db->next_written,
             "write less data than expected");

    pad_data_file(db);
    if (db->error)
        return -1;

    index.guard = GUARD;
    index.flags = WRITING;
    index.id = db->next_id;
    index.length = db->next_length + sizeof(data_t);
    index.offset = db->next_offset;

    ERRORP_IF(sizeof(index_t) != writen(db->index_fd, &index, sizeof(index_t)),
              "failed to write");

    content_len = db->index_len - sizeof(index_t);
    ERRORP_IF(content_len != writen(db->index_fd, content, content_len),
              "failed to write index content");

    db->index_file_len += db->index_len;
    remap_index_file(db, SIZE_MAX);
    if (db->error)
        return -1;

    indexp = RECORD_TO_INDEX(db, db->index_file_len - db->index_len);

    assert(GUARD == indexp->guard && WRITING == indexp->flags &&
           index.id == indexp->id && index.length == indexp->length &&
           index.offset == indexp->offset);

    indexp->flags = 0;

    return INDEX_TO_RECORD(db, indexp);

L_error:
    db->error = -1;
    return -1;
}
コード例 #5
0
ファイル: file_access.c プロジェクト: srimalik/samba
NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32 dosmode)
{
	/*
	 * Only allow delete on close for writable files.
	 */

	if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
	    !lp_delete_readonly(SNUM(fsp->conn))) {
		DEBUG(10,("can_set_delete_on_close: file %s delete on close "
			  "flag set but file attribute is readonly.\n",
			  fsp_str_dbg(fsp)));
		return NT_STATUS_CANNOT_DELETE;
	}

	/*
	 * Only allow delete on close for writable shares.
	 */

	if (!CAN_WRITE(fsp->conn)) {
		DEBUG(10,("can_set_delete_on_close: file %s delete on "
			  "close flag set but write access denied on share.\n",
			  fsp_str_dbg(fsp)));
		return NT_STATUS_ACCESS_DENIED;
	}

	/*
	 * Only allow delete on close for files/directories opened with delete
	 * intent.
	 */

	if (!(fsp->access_mask & DELETE_ACCESS)) {
		DEBUG(10,("can_set_delete_on_close: file %s delete on "
			  "close flag set but delete access denied.\n",
			  fsp_str_dbg(fsp)));
		return NT_STATUS_ACCESS_DENIED;
	}

	/* Don't allow delete on close for non-empty directories. */
	if (fsp->is_directory) {
		SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name));

		/* Or the root of a share. */
		if (ISDOT(fsp->fsp_name->base_name)) {
			DEBUG(10,("can_set_delete_on_close: can't set delete on "
				  "close for the root of a share.\n"));
			return NT_STATUS_ACCESS_DENIED;
		}

		return can_delete_directory(fsp->conn,
					    fsp->fsp_name->base_name);
	}

	return NT_STATUS_OK;
}
コード例 #6
0
ファイル: apdb.c プロジェクト: guoyu07/jff
void
apdb_delete(apdb_t* db, apdb_record_t record)
{
    index_t* index;

    assert(NULL != db && record >= 0 && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    index = RECORD_TO_INDEX(db, record);
    assert(GUARD == index->guard);

    index->flags |= DELETED;
}
コード例 #7
0
ファイル: apdb.c プロジェクト: guoyu07/jff
/**
 * make sure range [0, min(to, st_size)) of index file is mapped.
 *
 * @note Writer process always knows the current real size of index
 * file, but reader processes don't, so we need update @c index_file_len
 * when map window can't fully cover [0, to), the caller should
 * check @c index_file_len against @c to after calling this function to
 * make sure not access data out of file ending.
 */
static void
remap_index_file(apdb_t* db, size_t to)
{
    struct stat st;

    assert(NULL != db && 0 == db->error);

    if (! CAN_WRITE(db)) {
        /*
         * can't be to <= db->index_mmap_len, because st_size
         * can be changed by writer process and reader processes
         * use index_file_len to calculate count of records in
         * apdb_first() and apdb_next().
         */
        if (to <= db->index_file_len)
            return;

        ERRORP_IF(-1 == fstat(db->index_fd, &st),
                  "failed to fstat");

        db->index_file_len = st.st_size;
    } else if (to <= db->data_mmap_len) {
        /*
         * @note NEVER return if @c to <= db->index_file_len for writer
         * process because writer process increases index_file_len when
         * adding record but doesn't update map window before finishing.
         */
        return;
    }

    if (db->index_mmap_len < db->index_file_len) {
        ERRORP_IF(-1 == munmap(db->index_mmap, db->index_mmap_len),
                  "failed to munmap");

        db->index_mmap_len = db->index_file_len + INDEX_EXPAND_SIZE;

        /* mmap PROT_READ for client and PROT_READ | PROT_WRITE for server */
        db->index_mmap = mmap(NULL, db->index_mmap_len, db->prot,
                              MAP_SHARED, db->index_fd, 0);
        ERRORP_IF(MAP_FAILED == db->index_mmap,
                  "failed to mmap");
    }

    return;

L_error:
    db->error = -1;
}
コード例 #8
0
ファイル: dosmode.c プロジェクト: AllardJ/Tomato
int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
{
	SMB_STRUCT_STAT sbuf;
	int ret = -1;

	errno = 0;
	ZERO_STRUCT(sbuf);

	/* Don't update the time on read-only shares */
	/* We need this as set_filetime (which can be called on
	   close and other paths) can end up calling this function
	   without the NEED_WRITE protection. Found by : 
	   Leo Weppelman <*****@*****.**>
	*/

	if (!CAN_WRITE(conn)) {
		return 0;
	}

	if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES)) {
		return -1;
	}

	if(!lp_dos_filetimes(SNUM(conn))) {
		return -1;
	}

	/* We have permission (given by the Samba admin) to
	   break POSIX semantics and allow a user to change
	   the time on a file they don't own but can write to
	   (as DOS does).
	 */

	/* Check if we have write access. */
	if (can_write_to_file(conn, fname, &sbuf)) {
		/* We are allowed to become root and change the filetime. */
		become_root();
		ret = SMB_VFS_NTIMES(conn, fname, ts);
		unbecome_root();
	}

	return ret;
}
コード例 #9
0
ファイル: apdb.c プロジェクト: guoyu07/jff
unsigned
apdb_add_begin(apdb_t* db, size_t length)
{
    data_t data;

    assert(NULL != db && NONE == db->action && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    if (db->error)
        return -1;

    if (SSIZE_MAX - db->index_len <= db->index_file_len) {
        DEBUG("index file too big");
        return -1;
    }
    if (SSIZE_MAX - ALIGN_UP(sizeof(data_t) + length, ALIGN_SIZE) <=
            db->data_file_len) {
        DEBUG("data file too big");
        return -1;
    }

    db->next_id = get_next_id(db);
    if (db->error || UINT_MAX == db->next_id /* avoid overflow */)
        return -1;

    db->next_length = length;
    db->next_offset = db->data_file_len;
    db->next_written = 0;

    data.guard = GUARD;
    data.flags = 0;
    data.id = db->next_id;
    data.length = length;

    ERRORP_IF(sizeof(data_t) != writen(db->data_fd, &data, sizeof(data_t)),
              "failed to write");

    db->data_file_len += sizeof(data_t);
    db->action = ADD;

    return data.id;

L_error:
    db->error = -1;
    return -1;
}
コード例 #10
0
ファイル: apdb.c プロジェクト: guoyu07/jff
void
apdb_record_unlock(apdb_t* db, apdb_record_t record)
{
    index_t* index;

    assert(NULL != db && record >= 0 &&
           NONE == db->action && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    if (db->error)
        return;

    index = RECORD_TO_INDEX(db, record);
    assert(GUARD == index->guard && (WRITING & index->flags));

    index->flags &= ~WRITING;
}
コード例 #11
0
ファイル: apdb.c プロジェクト: guoyu07/jff
/**
 * make sure range [0, min(to, st_size)) of data file is mapped.
 *
 * @note Writer process always knows the current real size of data
 * file, but reader processes don't, so we need update @c data_file_len
 * when map window can't fully cover [0, to), the caller should
 * check @c data_file_len against @c to after calling this function to
 * make sure not access data out of file ending.
 */
static void
remap_data_file(apdb_t* db, size_t to)
{
    struct stat st;

    assert(NULL != db && 0 == db->error);

    /*
     * don't have to be to <= db->data_file_len, because
     * we don't use @c data_file_len to calculate count of records.
     *
     * @note db->data_file_len is always less or equal to st_size.
     *
     * @note NEVER return if @c to <= db->data_file_len for writer
     * process because writer process increases data_file_len when
     * adding record but doesn't update map window before finishing.
     */
    if (to <= db->data_mmap_len) {
        return;
    } else if (! CAN_WRITE(db)) {
        ERRORP_IF(-1 == fstat(db->data_fd, &st),
                  "failed to fstat");

        db->data_file_len = st.st_size;
    }

    if (db->data_mmap_len < db->data_file_len) {
        ERRORP_IF(MAP_FAILED != db->data_mmap &&
                    -1 == munmap(db->data_mmap, db->data_mmap_len),
                  "failed to munmap");

        db->data_mmap_len = db->data_file_len + DATA_EXPAND_SIZE;

        /* always mmap to read  */
        db->data_mmap = mmap(NULL, db->data_mmap_len, PROT_READ,
                              MAP_SHARED, db->data_fd, 0);
        ERRORP_IF(MAP_FAILED == db->data_mmap,
                  "failed to mmap");
    }

    return;

L_error:
    db->error = -1;
}
コード例 #12
0
ファイル: apdb.c プロジェクト: guoyu07/jff
int
apdb_record_set_flags(apdb_t* db, apdb_record_t record, unsigned flags)
{
    index_t* index;

    assert(NULL != db && record >= 0 && NONE == db->action && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    if (db->error)
        return -1;

    index = RECORD_TO_INDEX(db, record);
    assert(GUARD == index->guard);

    index->flags = flags & ~(WRITING | DELETED);

    return 0;
}
コード例 #13
0
ファイル: dosmode.c プロジェクト: AllardJ/Tomato
/*******************************************************************
Wrapper around dos_utime that possibly allows DOS semantics rather
than POSIX.
*******************************************************************/
int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
{
  extern struct current_user current_user;
  SMB_STRUCT_STAT sb;
  int ret = -1;

  errno = 0;

  if(dos_utime(fname, times) == 0)
    return 0;

  if((errno != EPERM) && (errno != EACCES))
    return -1;

  if(!lp_dos_filetimes(SNUM(conn)))
    return -1;

  /* We have permission (given by the Samba admin) to
     break POSIX semantics and allow a user to change
     the time on a file they don't own but can write to
     (as DOS does).
   */

  if(dos_stat(fname,&sb) != 0)
    return -1;

  /* Check if we have write access. */
  if (CAN_WRITE(conn)) {
	  if (((sb.st_mode & S_IWOTH) ||
	       conn->admin_user ||
	       ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
	       ((sb.st_mode & S_IWGRP) &&
		in_group(sb.st_gid,current_user.gid,
			 current_user.ngroups,current_user.groups)))) {
		  /* We are allowed to become root and change the filetime. */
		  become_root(False);
		  ret = dos_utime(fname, times);
		  unbecome_root(False);
	  }
  }

  return ret;
}
コード例 #14
0
ファイル: apdb.c プロジェクト: guoyu07/jff
int
apdb_update_begin(apdb_t* db, apdb_record_t record, size_t length)
{
    index_t* index;
    data_t data;

    assert(NULL != db && record >= 0 && NONE == db->action && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    if (db->error)
        return -1;

    if (SSIZE_MAX - ALIGN_UP(sizeof(data_t) + length, ALIGN_SIZE) <=
            db->data_file_len) {
        DEBUG("data file too big");
        return -1;
    }

    index = RECORD_TO_INDEX(db, record);
    assert(GUARD == index->guard);

    db->next_record = record;
    db->next_length = length;
    db->next_offset = db->data_file_len;
    db->next_written = 0;

    data.guard = GUARD;
    data.flags = index->flags;
    data.id = index->id;
    data.length = length;

    ERRORP_IF(sizeof(data_t) != writen(db->data_fd, &data, sizeof(data_t)),
              "failed to write");

    db->data_file_len += sizeof(data_t);
    db->action = UPDATE;

    return 0;

L_error:
    db->error = -1;
    return -1;
}
コード例 #15
0
ファイル: apdb.c プロジェクト: guoyu07/jff
/**
 * get next available id, 0 <= id < UINT_MAX
 *
 * @param db    pointer to a database instance
 *
 * @return UINT_MAX on error, next id on success
 *
 * @note This function can only be called by writer process
 * because only it knows the real last record.
 */
static unsigned
get_next_id(apdb_t* db)
{
    unsigned count;
    index_t* index;

    assert(NULL != db && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    if (0 == db->index_file_len)
        return 0;

    count = db->index_file_len / db->index_len;
    index = RECORD_TO_INDEX(db, (count - 1) * db->index_len);
    ERROR_IF(GUARD != index->guard || UINT_MAX == index->id, "corrupted index");

    return index->id + 1;

L_error:
    db->error = -1;
    return UINT_MAX;
}
コード例 #16
0
ファイル: apdb.c プロジェクト: guoyu07/jff
int
apdb_update_end(apdb_t* db, void* content)
{
    index_t* index;

    assert(NULL != db && UPDATE == db->action && CAN_WRITE(db));
    assert(db->index_file_len <= db->index_mmap_len);

    db->action = NONE;

    if (db->error)
        return -1;

    ERROR_IF(db->next_length != db->next_written,
             "write less data than expected");

    pad_data_file(db);
    if (db->error)
        return -1;

    index = RECORD_TO_INDEX(db, db->next_record);
    assert(GUARD == index->guard);

    index->flags |= WRITING;

    index->length = sizeof(data_t);  /* make reader processes read nothing */
    index->offset = db->next_offset;
    if (NULL != content)
        memcpy(index->content, content, db->index_len - sizeof(index_t));
    index->length += db->next_length;

    index->flags &= ~WRITING;

    return 0;

L_error:
    db->error = -1;
    return -1;
}
コード例 #17
0
ファイル: durable.c プロジェクト: hef/samba
NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
				       struct smb_request *smb1req,
				       struct smbXsrv_open *op,
				       const DATA_BLOB old_cookie,
				       TALLOC_CTX *mem_ctx,
				       files_struct **result,
				       DATA_BLOB *new_cookie)
{
	struct share_mode_lock *lck;
	struct share_mode_entry *e;
	struct files_struct *fsp = NULL;
	NTSTATUS status;
	bool ok;
	int ret;
	int flags = 0;
	struct file_id file_id;
	struct smb_filename *smb_fname = NULL;
	enum ndr_err_code ndr_err;
	struct vfs_default_durable_cookie cookie;
	DATA_BLOB new_cookie_blob = data_blob_null;

	*result = NULL;
	*new_cookie = data_blob_null;

	if (!lp_durable_handles(SNUM(conn))) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	/*
	 * the checks for kernel oplocks
	 * and similar things are done
	 * in the vfs_default_durable_cookie()
	 * call below.
	 */

	ZERO_STRUCT(cookie);

	ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
			(ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		return status;
	}

	if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!cookie.allow_reconnect) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/* Create an smb_filename with stream_name == NULL. */
	smb_fname = synthetic_smb_fname(talloc_tos(), cookie.base_name,
					NULL, NULL);
	if (smb_fname == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	ret = SMB_VFS_LSTAT(conn, smb_fname);
	if (ret == -1) {
		status = map_nt_error_from_unix_common(errno);
		DEBUG(1, ("Unable to lstat stream: %s => %s\n",
			  smb_fname_str_dbg(smb_fname),
			  nt_errstr(status)));
		return status;
	}

	if (!S_ISREG(smb_fname->st.st_ex_mode)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
	if (!file_id_equal(&cookie.id, &file_id)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/*
	 * 1. check entry in locking.tdb
	 */

	lck = get_existing_share_mode_lock(mem_ctx, file_id);
	if (lck == NULL) {
		DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
			   "not obtained from db\n"));
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (lck->data->num_share_modes == 0) {
		DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
			  "entry in existing share mode lock\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_INTERNAL_DB_ERROR;
	}

	if (lck->data->num_share_modes > 1) {
		/*
		 * It can't be durable if there is more than one handle
		 * on the file.
		 */
		DEBUG(5, ("vfs_default_durable_reconnect: more than one "
			  "share-mode entry - can not be durable\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	e = &lck->data->share_modes[0];

	if (!server_id_is_disconnected(&e->pid)) {
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "reconnect for handle that was not marked "
			  "disconnected (e.g. smbd or cluster node died)\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (e->share_file_id != op->global->open_persistent_id) {
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "share_file_id changed %llu != %llu"
			  "(e.g. another client had opened the file)\n",
			  (unsigned long long)e->share_file_id,
			  (unsigned long long)op->global->open_persistent_id));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
	    !CAN_WRITE(conn))
	{
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "share[%s] is not writeable anymore\n",
			  lp_servicename(talloc_tos(), SNUM(conn))));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/*
	 * 2. proceed with opening file
	 */

	status = fsp_new(conn, conn, &fsp);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
			  "new fsp: %s\n", nt_errstr(status)));
		TALLOC_FREE(lck);
		return status;
	}

	fsp->fh->private_options = e->private_options;
	fsp->fh->gen_id = smbXsrv_open_hash(op);
	fsp->file_id = file_id;
	fsp->file_pid = smb1req->smbpid;
	fsp->vuid = smb1req->vuid;
	fsp->open_time = e->time;
	fsp->access_mask = e->access_mask;
	fsp->share_access = e->share_access;
	fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
	fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
	fsp->fnum = op->local_id;

	/*
	 * TODO:
	 * Do we need to store the modified flag in the DB?
	 */
	fsp->modified = false;
	/*
	 * no durables for directories
	 */
	fsp->is_directory = false;
	/*
	 * For normal files, can_lock == !is_directory
	 */
	fsp->can_lock = true;
	/*
	 * We do not support aio write behind for smb2
	 */
	fsp->aio_write_behind = false;
	fsp->oplock_type = e->op_type;

	fsp->initial_allocation_size = cookie.initial_allocation_size;
	fsp->fh->position_information = cookie.position_information;
	fsp->update_write_time_triggered = cookie.update_write_time_triggered;
	fsp->update_write_time_on_close = cookie.update_write_time_on_close;
	fsp->write_time_forced = cookie.write_time_forced;
	fsp->close_write_time = cookie.close_write_time;

	status = fsp_set_smb_fname(fsp, smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		fsp_free(fsp);
		DEBUG(0, ("vfs_default_durable_reconnect: "
			  "fsp_set_smb_fname failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	op->compat = fsp;
	fsp->op = op;

	e->pid = messaging_server_id(conn->sconn->msg_ctx);
	e->op_mid = smb1req->mid;
	e->share_file_id = fsp->fh->gen_id;

	ok = brl_reconnect_disconnected(fsp);
	if (!ok) {
		status = NT_STATUS_INTERNAL_ERROR;
		DEBUG(1, ("vfs_default_durable_reconnect: "
			  "failed to reopen brlocks: %s\n",
			  nt_errstr(status)));
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	/*
	 * TODO: properly calculate open flags
	 */
	if (fsp->can_write && fsp->can_read) {
		flags = O_RDWR;
	} else if (fsp->can_write) {
		flags = O_WRONLY;
	} else if (fsp->can_read) {
		flags = O_RDONLY;
	}

	status = fd_open(conn, fsp, flags, 0 /* mode */);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
			  "file: %s\n", nt_errstr(status)));
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	/*
	 * We now check the stat info stored in the cookie against
	 * the current stat data from the file we just opened.
	 * If any detail differs, we deny the durable reconnect,
	 * because in that case it is very likely that someone
	 * opened the file while the handle was disconnected,
	 * which has to be interpreted as an oplock break.
	 */

	ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
	if (ret == -1) {
		status = map_nt_error_from_unix_common(errno);
		DEBUG(1, ("Unable to fstat stream: %s => %s\n",
			  smb_fname_str_dbg(smb_fname),
			  nt_errstr(status)));
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
	if (!file_id_equal(&cookie.id, &file_id)) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
						      &fsp->fsp_name->st,
						      fsp_str_dbg(fsp));
	if (!ok) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	status = set_file_oplock(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
			  "after opening file: %s\n", nt_errstr(status)));
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		DEBUG(1, ("vfs_default_durable_reconnect: "
			  "vfs_default_durable_cookie - %s\n",
			  nt_errstr(status)));
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	smb1req->chain_fsp = fsp;
	smb1req->smb2req->compat_chain_fsp = fsp;

	DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
		   fsp_str_dbg(fsp)));

	/*
	 * release the sharemode lock: this writes the changes
	 */
	lck->data->modified = true;
	TALLOC_FREE(lck);

	*result = fsp;
	*new_cookie = new_cookie_blob;

	return NT_STATUS_OK;
}
コード例 #18
0
ファイル: dosmode.c プロジェクト: abartlet/samba-old
int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
		     uint32 dosmode, const char *parent_dir, bool newfile)
{
	int mask=0;
	mode_t tmp;
	mode_t unixmode;
	int ret = -1, lret = -1;
	uint32_t old_mode;
	struct timespec new_create_timespec;
	files_struct *fsp = NULL;
	bool need_close = false;
	NTSTATUS status;

	if (!CAN_WRITE(conn)) {
		errno = EROFS;
		return -1;
	}

	/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
	dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);

	DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
		  dosmode, smb_fname_str_dbg(smb_fname)));

	unixmode = smb_fname->st.st_ex_mode;

	get_acl_group_bits(conn, smb_fname->base_name,
			   &smb_fname->st.st_ex_mode);

	if (S_ISDIR(smb_fname->st.st_ex_mode))
		dosmode |= FILE_ATTRIBUTE_DIRECTORY;
	else
		dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;

	new_create_timespec = smb_fname->st.st_ex_btime;

	old_mode = dos_mode(conn, smb_fname);

	if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
	    !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
		lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
		if (lret == -1) {
			if (errno == ENOTSUP) {
				DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
					   "%s/%s is not supported.\n",
					   parent_dir,
					   smb_fname_str_dbg(smb_fname)));
			} else {
				DEBUG(0, ("An error occurred while setting "
					  "FILE_ATTRIBUTE_OFFLINE for "
					  "%s/%s: %s", parent_dir,
					  smb_fname_str_dbg(smb_fname),
					  strerror(errno)));
			}
		}
	}

	dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
	old_mode &= ~FILE_ATTRIBUTE_OFFLINE;

	smb_fname->st.st_ex_btime = new_create_timespec;

	/* Store the DOS attributes in an EA by preference. */
	if (lp_store_dos_attributes(SNUM(conn))) {
		/*
		 * Don't fall back to using UNIX modes. Finally
		 * follow the smb.conf manpage.
		 */
		if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
			return -1;
		}
		if (!newfile) {
			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
				     FILE_NOTIFY_CHANGE_ATTRIBUTES,
				     smb_fname->base_name);
		}
		smb_fname->st.st_ex_mode = unixmode;
		return 0;
	}

	unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);

	/* preserve the file type bits */
	mask |= S_IFMT;

	/* preserve the s bits */
	mask |= (S_ISUID | S_ISGID);

	/* preserve the t bit */
#ifdef S_ISVTX
	mask |= S_ISVTX;
#endif

	/* possibly preserve the x bits */
	if (!MAP_ARCHIVE(conn))
		mask |= S_IXUSR;
	if (!MAP_SYSTEM(conn))
		mask |= S_IXGRP;
	if (!MAP_HIDDEN(conn))
		mask |= S_IXOTH;

	unixmode |= (smb_fname->st.st_ex_mode & mask);

	/* if we previously had any r bits set then leave them alone */
	if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
		unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
		unixmode |= tmp;
	}

	/* if we previously had any w bits set then leave them alone 
		whilst adding in the new w bits, if the new mode is not rdonly */
	if (!IS_DOS_READONLY(dosmode)) {
		unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
	}

	/*
	 * From the chmod 2 man page:
	 *
	 * "If the calling process is not privileged, and the group of the file
	 * does not match the effective group ID of the process or one of its
	 * supplementary group IDs, the S_ISGID bit will be turned off, but
	 * this will not cause an error to be returned."
	 *
	 * Simply refuse to do the chmod in this case.
	 */

	if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
			geteuid() != sec_initial_uid() &&
			!current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
		DEBUG(3,("file_set_dosmode: setgid bit cannot be "
			"set for directory %s\n",
			smb_fname_str_dbg(smb_fname)));
		errno = EPERM;
		return -1;
	}

	ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
	if (ret == 0) {
		if(!newfile || (lret != -1)) {
			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
				     FILE_NOTIFY_CHANGE_ATTRIBUTES,
				     smb_fname->base_name);
		}
		smb_fname->st.st_ex_mode = unixmode;
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES))
		return -1;

	if(!lp_dos_filemode(SNUM(conn)))
		return -1;

	/* We want DOS semantics, ie allow non owner with write permission to change the
		bits on a file. Just like file_ntimes below.
	*/

	if (!can_write_to_file(conn, smb_fname)) {
		errno = EACCES;
		return -1;
	}

	/*
	 * We need to get an open file handle to do the
	 * metadata operation under root.
	 */

	status = get_file_handle_for_metadata(conn,
					      smb_fname,
					      &fsp,
					      &need_close);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		return -1;
	}

	become_root();
	ret = SMB_VFS_FCHMOD(fsp, unixmode);
	unbecome_root();
	if (need_close) {
		close_file(NULL, fsp, NORMAL_CLOSE);
	}
	if (!newfile) {
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
			     smb_fname->base_name);
	}
	if (ret == 0) {
		smb_fname->st.st_ex_mode = unixmode;
	}

	return( ret );
}
コード例 #19
0
ファイル: dosmode.c プロジェクト: abartlet/samba-old
NTSTATUS file_set_sparse(connection_struct *conn,
			 files_struct *fsp,
			 bool sparse)
{
	uint32_t old_dosmode;
	uint32_t new_dosmode;
	NTSTATUS status;

	if (!CAN_WRITE(conn)) {
		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
			"on readonly share[%s]\n",
			smb_fname_str_dbg(fsp->fsp_name),
			sparse,
			lp_servicename(talloc_tos(), SNUM(conn))));
		return NT_STATUS_MEDIA_WRITE_PROTECTED;
	}

	/*
	 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
	 * following access flags are granted.
	 */
	if ((fsp->access_mask & (FILE_WRITE_DATA
				| FILE_WRITE_ATTRIBUTES
				| SEC_FILE_APPEND_DATA)) == 0) {
		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
			"access_mask[0x%08X] - access denied\n",
			smb_fname_str_dbg(fsp->fsp_name),
			sparse,
			fsp->access_mask));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (fsp->is_directory) {
		DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
			  (sparse ? "set" : "clear"),
			  smb_fname_str_dbg(fsp->fsp_name)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (IS_IPC(conn) || IS_PRINT(conn)) {
		DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
			  (sparse ? "set" : "clear")));
		return NT_STATUS_INVALID_PARAMETER;
	}

	DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
		  sparse, smb_fname_str_dbg(fsp->fsp_name)));

	if (!lp_store_dos_attributes(SNUM(conn))) {
		return NT_STATUS_INVALID_DEVICE_REQUEST;
	}

	status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	old_dosmode = dos_mode(conn, fsp->fsp_name);

	if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
		new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
	} else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
		new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
	} else {
		return NT_STATUS_OK;
	}

	/* Store the DOS attributes in an EA. */
	if (!set_ea_dos_attribute(conn, fsp->fsp_name,
				  new_dosmode)) {
		if (errno == 0) {
			errno = EIO;
		}
		return map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_MODIFIED,
		     FILE_NOTIFY_CHANGE_ATTRIBUTES,
		     fsp->fsp_name->base_name);

	fsp->is_sparse = sparse;

	return NT_STATUS_OK;
}
コード例 #20
0
ファイル: dosmode.c プロジェクト: andreas-gruenbacher/samba
static bool set_ea_dos_attribute(connection_struct *conn,
				 struct smb_filename *smb_fname,
				 uint32_t dosmode)
{
	struct xattr_DOSATTRIB dosattrib;
	enum ndr_err_code ndr_err;
	DATA_BLOB blob;

	ZERO_STRUCT(dosattrib);
	ZERO_STRUCT(blob);

	dosattrib.version = 3;
	dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
					XATTR_DOSINFO_CREATE_TIME;
	dosattrib.info.info3.attrib = dosmode;
	dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
				smb_fname->st.st_ex_btime);

	DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
		(unsigned int)dosmode,
		time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
		smb_fname_str_dbg(smb_fname) ));

	ndr_err = ndr_push_struct_blob(
			&blob, talloc_tos(), &dosattrib,
			(ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);

	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
			ndr_errstr(ndr_err)));
		return false;
	}

	if (blob.data == NULL || blob.length == 0) {
		return false;
	}

	if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
			     SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
			     0) == -1) {
		bool ret = false;
		bool need_close = false;
		files_struct *fsp = NULL;

		if((errno != EPERM) && (errno != EACCES)) {
			DBG_INFO("Cannot set "
				 "attribute EA on file %s: Error = %s\n",
				 smb_fname_str_dbg(smb_fname), strerror(errno));
			return false;
		}

		/* We want DOS semantics, ie allow non owner with write permission to change the
			bits on a file. Just like file_ntimes below.
		*/

		/* Check if we have write access. */
		if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
			return false;

		if (!can_write_to_file(conn, smb_fname)) {
			return false;
		}

		/*
		 * We need to get an open file handle to do the
		 * metadata operation under root.
		 */

		if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn,
						smb_fname,
						&fsp,
						&need_close))) {
			return false;
		}

		become_root();
		if (SMB_VFS_FSETXATTR(fsp,
				     SAMBA_XATTR_DOS_ATTRIB, blob.data,
				     blob.length, 0) == 0) {
			ret = true;
		}
		unbecome_root();
		if (need_close) {
			close_file(NULL, fsp, NORMAL_CLOSE);
		}
		return ret;
	}
	DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
		(unsigned int)dosmode,
		smb_fname_str_dbg(smb_fname)));
	return true;
}
コード例 #21
0
ファイル: dosmode.c プロジェクト: abartlet/samba-old
static bool get_ea_dos_attribute(connection_struct *conn,
				 struct smb_filename *smb_fname,
				 uint32 *pattr)
{
	struct xattr_DOSATTRIB dosattrib;
	enum ndr_err_code ndr_err;
	DATA_BLOB blob;
	ssize_t sizeret;
	fstring attrstr;
	uint32_t dosattr;

	if (!lp_store_dos_attributes(SNUM(conn))) {
		return False;
	}

	/* Don't reset pattr to zero as we may already have filename-based attributes we
	   need to preserve. */

	sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
				   SAMBA_XATTR_DOS_ATTRIB, attrstr,
				   sizeof(attrstr));
	if (sizeret == -1) {
		if (errno == ENOSYS
#if defined(ENOTSUP)
			|| errno == ENOTSUP) {
#else
				) {
#endif
			DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
				 "from EA on file %s: Error = %s\n",
				 smb_fname_str_dbg(smb_fname),
				 strerror(errno)));
			set_store_dos_attributes(SNUM(conn), False);
		}
		return False;
	}

	blob.data = (uint8_t *)attrstr;
	blob.length = sizeret;

	ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
			(ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);

	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
			 "from EA on file %s: Error = %s\n",
			 smb_fname_str_dbg(smb_fname),
			 ndr_errstr(ndr_err)));
		return false;
	}

	DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
		  smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));

	switch (dosattrib.version) {
		case 0xFFFF:
			dosattr = dosattrib.info.compatinfoFFFF.attrib;
			break;
		case 1:
			dosattr = dosattrib.info.info1.attrib;
			if (!null_nttime(dosattrib.info.info1.create_time)) {
				struct timespec create_time =
					nt_time_to_unix_timespec(
						dosattrib.info.info1.create_time);

				update_stat_ex_create_time(&smb_fname->st,
							create_time);

				DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
					"set btime %s\n",
					smb_fname_str_dbg(smb_fname),
					time_to_asc(convert_timespec_to_time_t(
						create_time)) ));
			}
			break;
		case 2:
			dosattr = dosattrib.info.oldinfo2.attrib;
			/* Don't know what flags to check for this case. */
			break;
		case 3:
			dosattr = dosattrib.info.info3.attrib;
			if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
					!null_nttime(dosattrib.info.info3.create_time)) {
				struct timespec create_time =
					nt_time_to_unix_timespec(
						dosattrib.info.info3.create_time);

				update_stat_ex_create_time(&smb_fname->st,
							create_time);

				DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
					"set btime %s\n",
					smb_fname_str_dbg(smb_fname),
					time_to_asc(convert_timespec_to_time_t(
						create_time)) ));
			}
			break;
		default:
			DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
				 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
				 attrstr));
	                return false;
	}

	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
		dosattr |= FILE_ATTRIBUTE_DIRECTORY;
	}
	/* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
	*pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));

	DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));

	if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
	if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
	if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
	if (dosattr & FILE_ATTRIBUTE_DIRECTORY   ) DEBUG(8, ("d"));
	if (dosattr & FILE_ATTRIBUTE_ARCHIVE  ) DEBUG(8, ("a"));

	DEBUG(8,("\n"));

	return True;
}

/****************************************************************************
 Set DOS attributes in an EA.
 Also sets the create time.
****************************************************************************/

static bool set_ea_dos_attribute(connection_struct *conn,
				 struct smb_filename *smb_fname,
				 uint32 dosmode)
{
	struct xattr_DOSATTRIB dosattrib;
	enum ndr_err_code ndr_err;
	DATA_BLOB blob;

	ZERO_STRUCT(dosattrib);
	ZERO_STRUCT(blob);

	dosattrib.version = 3;
	dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
					XATTR_DOSINFO_CREATE_TIME;
	dosattrib.info.info3.attrib = dosmode;
	dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
				smb_fname->st.st_ex_btime);

	DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
		(unsigned int)dosmode,
		time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
		smb_fname_str_dbg(smb_fname) ));

	ndr_err = ndr_push_struct_blob(
			&blob, talloc_tos(), &dosattrib,
			(ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);

	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
			ndr_errstr(ndr_err)));
		return false;
	}

	if (blob.data == NULL || blob.length == 0) {
		return false;
	}

	if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
			     SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
			     0) == -1) {
		bool ret = false;
		bool need_close = false;
		files_struct *fsp = NULL;

		if((errno != EPERM) && (errno != EACCES)) {
			if (errno == ENOSYS
#if defined(ENOTSUP)
				|| errno == ENOTSUP) {
#else
				) {
#endif
				DEBUG(1,("set_ea_dos_attributes: Cannot set "
					 "attribute EA on file %s: Error = %s\n",
					 smb_fname_str_dbg(smb_fname),
					 strerror(errno) ));
				set_store_dos_attributes(SNUM(conn), False);
			}
			return false;
		}

		/* We want DOS semantics, ie allow non owner with write permission to change the
			bits on a file. Just like file_ntimes below.
		*/

		/* Check if we have write access. */
		if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
			return false;

		if (!can_write_to_file(conn, smb_fname)) {
			return false;
		}

		/*
		 * We need to get an open file handle to do the
		 * metadata operation under root.
		 */

		if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn,
						smb_fname,
						&fsp,
						&need_close))) {
			return false;
		}

		become_root();
		if (SMB_VFS_FSETXATTR(fsp,
				     SAMBA_XATTR_DOS_ATTRIB, blob.data,
				     blob.length, 0) == 0) {
			ret = true;
		}
		unbecome_root();
		if (need_close) {
			close_file(NULL, fsp, NORMAL_CLOSE);
		}
		return ret;
	}
	DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
		(unsigned int)dosmode,
		smb_fname_str_dbg(smb_fname)));
	return true;
}

/****************************************************************************
 Change a unix mode to a dos mode for an ms dfs link.
****************************************************************************/

uint32 dos_mode_msdfs(connection_struct *conn,
		      const struct smb_filename *smb_fname)
{
	uint32 result = 0;

	DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));

	if (!VALID_STAT(smb_fname->st)) {
		return 0;
	}

	/* First do any modifications that depend on the path name. */
	/* hide files with a name starting with a . */
	if (lp_hide_dot_files(SNUM(conn))) {
		const char *p = strrchr_m(smb_fname->base_name, '/');
		if (p) {
			p++;
		} else {
			p = smb_fname->base_name;
		}

		/* Only . and .. are not hidden. */
		if (p[0] == '.' && !((p[1] == '\0') ||
				(p[1] == '.' && p[2] == '\0'))) {
			result |= FILE_ATTRIBUTE_HIDDEN;
		}
	}

	result |= dos_mode_from_sbuf(conn, smb_fname);

	/* Optimization : Only call is_hidden_path if it's not already
	   hidden. */
	if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
	    IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
		result |= FILE_ATTRIBUTE_HIDDEN;
	}

	if (result == 0) {
		result = FILE_ATTRIBUTE_NORMAL;
	}

	result = filter_mode_by_protocol(result);

	/*
	 * Add in that it is a reparse point
	 */
	result |= FILE_ATTRIBUTE_REPARSE_POINT;

	DEBUG(8,("dos_mode_msdfs returning "));

	if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
	if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
	if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
	if (result & FILE_ATTRIBUTE_DIRECTORY   ) DEBUG(8, ("d"));
	if (result & FILE_ATTRIBUTE_ARCHIVE  ) DEBUG(8, ("a"));
	if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));

	DEBUG(8,("\n"));

	return(result);
}
コード例 #22
0
ファイル: dosmode.c プロジェクト: AllardJ/Tomato
int file_set_dosmode(connection_struct *conn, const char *fname,
		     uint32 dosmode, SMB_STRUCT_STAT *st,
		     const char *parent_dir)
{
	SMB_STRUCT_STAT st1;
	int mask=0;
	mode_t tmp;
	mode_t unixmode;
	int ret = -1;

	/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
	dosmode &= SAMBA_ATTRIBUTES_MASK;

	DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));

	if (st == NULL) {
		SET_STAT_INVALID(st1);
		st = &st1;
	}

	if (!VALID_STAT(*st)) {
		if (SMB_VFS_STAT(conn,fname,st))
			return(-1);
	}

	unixmode = st->st_mode;

	get_acl_group_bits(conn, fname, &st->st_mode);

	if (S_ISDIR(st->st_mode))
		dosmode |= aDIR;
	else
		dosmode &= ~aDIR;

	if (dos_mode(conn,fname,st) == dosmode) {
		st->st_mode = unixmode;
		return(0);
	}

	/* Store the DOS attributes in an EA by preference. */
	if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
		st->st_mode = unixmode;
		return 0;
	}

	unixmode = unix_mode(conn,dosmode,fname, parent_dir);

	/* preserve the s bits */
	mask |= (S_ISUID | S_ISGID);

	/* preserve the t bit */
#ifdef S_ISVTX
	mask |= S_ISVTX;
#endif

	/* possibly preserve the x bits */
	if (!MAP_ARCHIVE(conn))
		mask |= S_IXUSR;
	if (!MAP_SYSTEM(conn))
		mask |= S_IXGRP;
	if (!MAP_HIDDEN(conn))
		mask |= S_IXOTH;

	unixmode |= (st->st_mode & mask);

	/* if we previously had any r bits set then leave them alone */
	if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
		unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
		unixmode |= tmp;
	}

	/* if we previously had any w bits set then leave them alone 
		whilst adding in the new w bits, if the new mode is not rdonly */
	if (!IS_DOS_READONLY(dosmode)) {
		unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
	}

	if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
		st->st_mode = unixmode;
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES))
		return -1;

	if(!lp_dos_filemode(SNUM(conn)))
		return -1;

	/* We want DOS semantics, ie allow non owner with write permission to change the
		bits on a file. Just like file_ntimes below.
	*/

	/* Check if we have write access. */
	if (CAN_WRITE(conn)) {
		/*
		 * We need to open the file with write access whilst
		 * still in our current user context. This ensures we
		 * are not violating security in doing the fchmod.
		 * This file open does *not* break any oplocks we are
		 * holding. We need to review this.... may need to
		 * break batch oplocks open by others. JRA.
		 */
		files_struct *fsp;
		if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,st,&fsp)))
			return -1;
		become_root();
		ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
		unbecome_root();
		close_file_fchmod(fsp);
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
		if (ret == 0) {
			st->st_mode = unixmode;
		}
	}

	return( ret );
}
コード例 #23
0
ファイル: dosmode.c プロジェクト: AllardJ/Tomato
static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
{
	fstring attrstr;
	files_struct *fsp = NULL;
	BOOL ret = False;

	if (!lp_store_dos_attributes(SNUM(conn))) {
		return False;
	}

	snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
	if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
		if((errno != EPERM) && (errno != EACCES)) {
			if (errno == ENOSYS
#if defined(ENOTSUP)
				|| errno == ENOTSUP) {
#else
				) {
#endif
				set_store_dos_attributes(SNUM(conn), False);
			}
			return False;
		}

		/* We want DOS semantics, ie allow non owner with write permission to change the
			bits on a file. Just like file_ntimes below.
		*/

		/* Check if we have write access. */
		if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
			return False;

		/*
		 * We need to open the file with write access whilst
		 * still in our current user context. This ensures we
		 * are not violating security in doing the setxattr.
		 */

		if (!NT_STATUS_IS_OK(open_file_fchmod(conn,path,sbuf,&fsp)))
			return ret;
		become_root();
		if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
			ret = True;
		}
		unbecome_root();
		close_file_fchmod(fsp);
		return ret;
	}
	DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
	return True;
}

/****************************************************************************
 Change a unix mode to a dos mode for an ms dfs link.
****************************************************************************/

uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
{
	uint32 result = 0;

	DEBUG(8,("dos_mode_msdfs: %s\n", path));

	if (!VALID_STAT(*sbuf)) {
		return 0;
	}

	/* First do any modifications that depend on the path name. */
	/* hide files with a name starting with a . */
	if (lp_hide_dot_files(SNUM(conn))) {
		const char *p = strrchr_m(path,'/');
		if (p) {
			p++;
		} else {
			p = path;
		}
		
		if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
			result |= aHIDDEN;
		}
	}
	
	result |= dos_mode_from_sbuf(conn, path, sbuf);

	/* Optimization : Only call is_hidden_path if it's not already
	   hidden. */
	if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
		result |= aHIDDEN;
	}

	DEBUG(8,("dos_mode_msdfs returning "));

	if (result & aHIDDEN) DEBUG(8, ("h"));
	if (result & aRONLY ) DEBUG(8, ("r"));
	if (result & aSYSTEM) DEBUG(8, ("s"));
	if (result & aDIR   ) DEBUG(8, ("d"));
	if (result & aARCH  ) DEBUG(8, ("a"));
	if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
	
	DEBUG(8,("\n"));

	return(result);
}
コード例 #24
0
ファイル: file_access.c プロジェクト: srimalik/samba
bool can_delete_file_in_directory(connection_struct *conn,
				  const struct smb_filename *smb_fname)
{
	TALLOC_CTX *ctx = talloc_tos();
	char *dname = NULL;
	struct smb_filename *smb_fname_parent = NULL;
	NTSTATUS status;
	bool ret;

	if (!CAN_WRITE(conn)) {
		return False;
	}

	if (!lp_acl_check_permissions(SNUM(conn))) {
		/* This option means don't check. */
		return true;
	}

	/* Get the parent directory permission mask and owners. */
	if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) {
		return False;
	}

	status = create_synthetic_smb_fname(ctx, dname, NULL, NULL,
					    &smb_fname_parent);
	if (!NT_STATUS_IS_OK(status)) {
		ret = false;
		goto out;
	}

	if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
		ret = false;
		goto out;
	}

	/* fast paths first */

	if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) {
		ret = false;
		goto out;
	}
	if (get_current_uid(conn) == (uid_t)0) {
		/* I'm sorry sir, I didn't know you were root... */
		ret = true;
		goto out;
	}

#ifdef S_ISVTX
	/* sticky bit means delete only by owner of file or by root or
	 * by owner of directory. */
	if (smb_fname_parent->st.st_ex_mode & S_ISVTX) {
		if (!VALID_STAT(smb_fname->st)) {
			/* If the file doesn't already exist then
			 * yes we'll be able to delete it. */
			ret = true;
			goto out;
		}

		/*
		 * Patch from SATOH Fumiyasu <*****@*****.**>
		 * for bug #3348. Don't assume owning sticky bit
		 * directory means write access allowed.
		 * Fail to delete if we're not the owner of the file,
		 * or the owner of the directory as we have no possible
		 * chance of deleting. Otherwise, go on and check the ACL.
		 */
		if ((get_current_uid(conn) !=
			smb_fname_parent->st.st_ex_uid) &&
		    (get_current_uid(conn) != smb_fname->st.st_ex_uid)) {
			DEBUG(10,("can_delete_file_in_directory: not "
				  "owner of file %s or directory %s",
				  smb_fname_str_dbg(smb_fname),
				  smb_fname_str_dbg(smb_fname_parent)));
			ret = false;
			goto out;
		}
	}
#endif

	/* now for ACL checks */

	/*
	 * There's two ways to get the permission to delete a file: First by
	 * having the DELETE bit on the file itself and second if that does
	 * not help, by the DELETE_CHILD bit on the containing directory.
	 *
	 * Here we only check the directory permissions, we will
	 * check the file DELETE permission separately.
	 */

	ret = NT_STATUS_IS_OK(smbd_check_access_rights(conn,
				smb_fname_parent,
				FILE_DELETE_CHILD));
 out:
	TALLOC_FREE(dname);
	TALLOC_FREE(smb_fname_parent);
	return ret;
}
コード例 #25
0
ファイル: file_access.c プロジェクト: gojdic/samba
bool can_delete_file_in_directory(connection_struct *conn, const char *fname)
{
	SMB_STRUCT_STAT sbuf;
	TALLOC_CTX *ctx = talloc_tos();
	char *dname = NULL;

	if (!CAN_WRITE(conn)) {
		return False;
	}

	/* Get the parent directory permission mask and owners. */
	if (!parent_dirname(ctx, fname, &dname, NULL)) {
		return False;
	}
	if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
		return False;
	}

	/* fast paths first */

	if (!S_ISDIR(sbuf.st_mode)) {
		return False;
	}
	if (conn->server_info->utok.uid == 0 || conn->admin_user) {
		/* I'm sorry sir, I didn't know you were root... */
		return True;
	}

#ifdef S_ISVTX
	/* sticky bit means delete only by owner or root. */
	if (sbuf.st_mode & S_ISVTX) {
		SMB_STRUCT_STAT sbuf_file;
		if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
			if (errno == ENOENT) {
				/* If the file doesn't already exist then
				 * yes we'll be able to delete it. */
				return True;
			}
			return False;
		}
		/*
		 * Patch from SATOH Fumiyasu <*****@*****.**>
		 * for bug #3348. Don't assume owning sticky bit
		 * directory means write access allowed.
		 */
		if (conn->server_info->utok.uid != sbuf_file.st_uid) {
			return False;
		}
	}
#endif

	/* now for ACL checks */

	/*
	 * There's two ways to get the permission to delete a file: First by
	 * having the DELETE bit on the file itself and second if that does
	 * not help, by the DELETE_CHILD bit on the containing directory.
	 *
	 * Here we only check the directory permissions, we will
	 * check the file DELETE permission separately.
	 */

	return can_access_file_acl(conn, dname, FILE_DELETE_CHILD);
}
コード例 #26
0
ファイル: open.c プロジェクト: jophxy/samba
static BOOL open_file(files_struct *fsp,connection_struct *conn,
		      const char *fname1,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access)
{
	extern struct current_user current_user;
	pstring fname;
	int accmode = (flags & O_ACCMODE);
	int local_flags = flags;

	fsp->fd = -1;
	fsp->oplock_type = NO_OPLOCK;
	errno = EPERM;

	pstrcpy(fname,fname1);

	/* Check permissions */

	/*
	 * This code was changed after seeing a client open request 
	 * containing the open mode of (DENY_WRITE/read-only) with
	 * the 'create if not exist' bit set. The previous code
	 * would fail to open the file read only on a read-only share
	 * as it was checking the flags parameter  directly against O_RDONLY,
	 * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
	 * JRA.
	 */

	if (!CAN_WRITE(conn)) {
		/* It's a read-only share - fail if we wanted to write. */
		if(accmode != O_RDONLY) {
			DEBUG(3,("Permission denied opening %s\n",fname));
			check_for_pipe(fname);
			return False;
		} else if(flags & O_CREAT) {
			/* We don't want to write - but we must make sure that O_CREAT
			   doesn't create the file if we have write access into the
			   directory.
			*/
			flags &= ~O_CREAT;
		}
	}

	/*
	 * This little piece of insanity is inspired by the
	 * fact that an NT client can open a file for O_RDONLY,
	 * but set the create disposition to FILE_EXISTS_TRUNCATE.
	 * If the client *can* write to the file, then it expects to
	 * truncate the file, even though it is opening for readonly.
	 * Quicken uses this stupid trick in backup file creation...
	 * Thanks *greatly* to "David W. Chapman Jr." <*****@*****.**>
	 * for helping track this one down. It didn't bite us in 2.0.x
	 * as we always opened files read-write in that release. JRA.
	 */

	if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
		DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname ));
		local_flags = (flags & ~O_ACCMODE)|O_RDWR;
	}

	/* actually do the open */

	if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
			(local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) {

		/*
		 * We can't actually truncate here as the file may be locked.
		 * open_file_shared will take care of the truncate later. JRA.
		 */

		local_flags &= ~O_TRUNC;

#if defined(O_NONBLOCK) && defined(S_ISFIFO)
		/*
		 * We would block on opening a FIFO with no one else on the
		 * other end. Do what we used to do and add O_NONBLOCK to the
		 * open flags. JRA.
		 */

		if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode))
			local_flags |= O_NONBLOCK;
#endif
		fsp->fd = fd_open(conn, fname, local_flags, mode);

		if (fsp->fd == -1)  {
			DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n",
				 fname,strerror(errno),local_flags,flags));
			check_for_pipe(fname);
			return False;
		}
	} else
		fsp->fd = -1; /* What we used to call a stat open. */

	if (!VALID_STAT(*psbuf)) {
		int ret;

		if (fsp->fd == -1)
			ret = vfs_stat(conn, fname, psbuf);
		else {
			ret = vfs_fstat(fsp,fsp->fd,psbuf);
			/* If we have an fd, this stat should succeed. */
			if (ret == -1)
				DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) ));
		}

		/* For a non-io open, this stat failing means file not found. JRA */
		if (ret == -1) {
			fd_close(conn, fsp);
			return False;
		}
	}

	/*
	 * POSIX allows read-only opens of directories. We don't
	 * want to do this (we use a different code path for this)
	 * so catch a directory open and return an EISDIR. JRA.
	 */

	if(S_ISDIR(psbuf->st_mode)) {
		fd_close(conn, fsp);
		errno = EISDIR;
		return False;
	}

	fsp->mode = psbuf->st_mode;
	fsp->inode = psbuf->st_ino;
	fsp->dev = psbuf->st_dev;
	fsp->vuid = current_user.vuid;
	fsp->size = psbuf->st_size;
	fsp->pos = -1;
	fsp->can_lock = True;
	fsp->can_read = ((flags & O_WRONLY)==0);
	fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
	fsp->share_mode = 0;
	fsp->desired_access = desired_access;
	fsp->print_file = False;
	fsp->modified = False;
	fsp->oplock_type = NO_OPLOCK;
	fsp->sent_oplock_break = NO_BREAK_SENT;
	fsp->is_directory = False;
	fsp->directory_delete_on_close = False;
	fsp->conn = conn;
	/*
	 * Note that the file name here is the *untranslated* name
	 * ie. it is still in the DOS codepage sent from the client.
	 * All use of this filename will pass though the sys_xxxx
	 * functions which will do the dos_to_unix translation before
	 * mapping into a UNIX filename. JRA.
	 */
	string_set(&fsp->fsp_name,fname);
	fsp->wbmpx_ptr = NULL;      
	fsp->wcp = NULL; /* Write cache pointer. */

	DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
		 *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name,
		 BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
		 conn->num_files_open + 1));

	return True;
}