Commit message: CVE-2021-44142: smbd: add Netatalk xattr used by vfs_fruit to the list of private Samba xattrs

This is an internal xattr that should not be user visible.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
CVE: None
CWE: CWE-787
Vulnerability description: None

Project: samba
File: trans2.c

static NTSTATUS smb_posix_unlink(connection_struct *conn,
				 struct smb_request *req,
				const char *pdata,
				int total_data,
				struct smb_filename *smb_fname)
{
	NTSTATUS status = NT_STATUS_OK;
	files_struct *fsp = NULL;
	uint16_t flags = 0;
	char del = 1;
	int info = 0;
	int create_options = 0;
	struct share_mode_lock *lck = NULL;
	bool other_nonposix_opens;
	struct smb2_create_blobs *posx = NULL;

	if (total_data < 2) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	flags = SVAL(pdata,0);

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

	if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
			!VALID_STAT_OF_DIR(smb_fname->st)) {
		return NT_STATUS_NOT_A_DIRECTORY;
	}

	DEBUG(10,("smb_posix_unlink: %s %s\n",
		(flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
		smb_fname_str_dbg(smb_fname)));

	if (VALID_STAT_OF_DIR(smb_fname->st)) {
		create_options |= FILE_DIRECTORY_FILE;
	}

	status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
			    nt_errstr(status));
		return status;
	}

        status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		DELETE_ACCESS,				/* access_mask */
		(FILE_SHARE_READ | FILE_SHARE_WRITE |	/* share_access */
		    FILE_SHARE_DELETE),
		FILE_OPEN,				/* create_disposition*/
		create_options,				/* create_options */
		0,					/* file_attributes */
		0,					/* oplock_request */
		NULL,					/* lease */
		0,					/* allocation_size */
		0,					/* private_flags */
		NULL,					/* sd */
		NULL,					/* ea_list */
		&fsp,					/* result */
		&info,					/* pinfo */
		posx,					/* in_context_blobs */
		NULL);					/* out_context_blobs */

	TALLOC_FREE(posx);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/*
	 * Don't lie to client. If we can't really delete due to
	 * non-POSIX opens return SHARING_VIOLATION.
	 */

	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck == NULL) {
		DEBUG(0, ("smb_posix_unlink: Could not get share mode "
			  "lock for file %s\n", fsp_str_dbg(fsp)));
		close_file(req, fsp, NORMAL_CLOSE);
		return NT_STATUS_INVALID_PARAMETER;
	}

	other_nonposix_opens = has_other_nonposix_opens(lck, fsp);
	if (other_nonposix_opens) {
		/* Fail with sharing violation. */
		TALLOC_FREE(lck);
		close_file(req, fsp, NORMAL_CLOSE);
		return NT_STATUS_SHARING_VIOLATION;
	}

	/*
	 * Set the delete on close.
	 */
	status = smb_set_file_disposition_info(conn,
						&del,
						1,
						fsp,
						smb_fname);

	TALLOC_FREE(lck);

	if (!NT_STATUS_IS_OK(status)) {
		close_file(req, fsp, NORMAL_CLOSE);
		return status;
	}
	return close_file(req, fsp, NORMAL_CLOSE);
}

Project: samba
File: trans2.c

static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
{
	struct ea_list *ea_list_head = NULL;
	size_t converted_size, offset = 0;

	while (offset + 2 < data_size) {
		struct ea_list *eal = talloc_zero(ctx, struct ea_list);
		unsigned int namelen = CVAL(pdata,offset);

		offset++; /* Go past the namelen byte. */

		/* integer wrap paranioa. */
		if ((offset + namelen < offset) || (offset + namelen < namelen) ||
				(offset > data_size) || (namelen > data_size) ||
				(offset + namelen >= data_size)) {
			break;
		}
		/* Ensure the name is null terminated. */
		if (pdata[offset + namelen] != '\0') {
			return NULL;
		}
		if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
				       &converted_size)) {
			DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
				 "failed: %s", strerror(errno)));
		}
		if (!eal->ea.name) {
			return NULL;
		}

		offset += (namelen + 1); /* Go past the name + terminating zero. */
		DLIST_ADD_END(ea_list_head, eal);
		DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
	}

	return ea_list_head;
}

Project: samba
File: trans2.c

static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
{
	int entry_id = SMB_ACL_FIRST_ENTRY;
	SMB_ACL_ENTRY_T entry;

	while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
		SMB_ACL_TAG_T tagtype;
		SMB_ACL_PERMSET_T permset;
		unsigned char perms = 0;
		unsigned int own_grp;

		/* get_next... */
		if (entry_id == SMB_ACL_FIRST_ENTRY) {
			entry_id = SMB_ACL_NEXT_ENTRY;
		}

		if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
			DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
			return False;
		}

		if (sys_acl_get_permset(entry, &permset) == -1) {
			DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
			return False;
		}

		perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
		perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
		perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);

		SCVAL(pdata,1,perms);

		switch (tagtype) {
			case SMB_ACL_USER_OBJ:
				SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
				own_grp = (unsigned int)pst->st_ex_uid;
				SIVAL(pdata,2,own_grp);
				SIVAL(pdata,6,0);
				break;
			case SMB_ACL_USER:
				{
					uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
					if (!puid) {
						DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
						return False;
					}
					own_grp = (unsigned int)*puid;
					SCVAL(pdata,0,SMB_POSIX_ACL_USER);
					SIVAL(pdata,2,own_grp);
					SIVAL(pdata,6,0);
					break;
				}
			case SMB_ACL_GROUP_OBJ:
				SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
				own_grp = (unsigned int)pst->st_ex_gid;
				SIVAL(pdata,2,own_grp);
				SIVAL(pdata,6,0);
				break;
			case SMB_ACL_GROUP:
				{
					gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
					if (!pgid) {
						DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
						return False;
					}
					own_grp = (unsigned int)*pgid;
					SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
					SIVAL(pdata,2,own_grp);
					SIVAL(pdata,6,0);
					break;
				}
			case SMB_ACL_MASK:
				SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
				SIVAL(pdata,2,0xFFFFFFFF);
				SIVAL(pdata,6,0xFFFFFFFF);
				break;
			case SMB_ACL_OTHER:
				SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
				SIVAL(pdata,2,0xFFFFFFFF);
				SIVAL(pdata,6,0xFFFFFFFF);
				break;
			default:
				DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
				return False;
		}
		pdata += SMB_POSIX_ACL_ENTRY_SIZE;
	}

	return True;
}

Project: samba
File: trans2.c

static void canonicalize_ea_name(files_struct *fsp,
			fstring unix_ea_name)
{
	size_t total_ea_len;
	TALLOC_CTX *mem_ctx = talloc_tos();
	struct ea_list *ea_list;
	NTSTATUS status = get_ea_list_from_fsp(mem_ctx,
					       fsp,
					       &total_ea_len,
					       &ea_list);
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	for (; ea_list; ea_list = ea_list->next) {
		if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
			DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
				&unix_ea_name[5], ea_list->ea.name));
			strlcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-5);
			break;
		}
	}
}

Project: samba
File: trans2.c

static NTSTATUS smb_posix_mkdir(connection_struct *conn,
				struct smb_request *req,
				char **ppdata,
				int total_data,
				struct smb_filename *smb_fname,
				int *pdata_return_size)
{
	NTSTATUS status = NT_STATUS_OK;
	uint32_t raw_unixmode = 0;
	mode_t unixmode = (mode_t)0;
	files_struct *fsp = NULL;
	uint16_t info_level_return = 0;
	int info;
	char *pdata = *ppdata;
	struct smb2_create_blobs *posx = NULL;

	if (total_data < 18) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	raw_unixmode = IVAL(pdata,8);
	/* Next 4 bytes are not yet defined. */

	status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
				      PERM_NEW_DIR, &unixmode);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
			    nt_errstr(status));
		return status;
	}

	DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
		  smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));

        status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		FILE_READ_ATTRIBUTES,			/* access_mask */
		FILE_SHARE_NONE,			/* share_access */
		FILE_CREATE,				/* create_disposition*/
		FILE_DIRECTORY_FILE,			/* create_options */
		0,					/* file_attributes */
		0,					/* oplock_request */
		NULL,					/* lease */
		0,					/* allocation_size */
		0,					/* private_flags */
		NULL,					/* sd */
		NULL,					/* ea_list */
		&fsp,					/* result */
		&info,					/* pinfo */
		posx,					/* in_context_blobs */
		NULL);					/* out_context_blobs */

	TALLOC_FREE(posx);

        if (NT_STATUS_IS_OK(status)) {
                close_file(req, fsp, NORMAL_CLOSE);
        }

	info_level_return = SVAL(pdata,16);
 
	if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
		*pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
	} else if (info_level_return ==  SMB_QUERY_FILE_UNIX_INFO2) {
		*pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
	} else {
		*pdata_return_size = 12;
	}

	/* Realloc the data size */
	*ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
	if (*ppdata == NULL) {
		*pdata_return_size = 0;
		return NT_STATUS_NO_MEMORY;
	}
	pdata = *ppdata;

	SSVAL(pdata,0,NO_OPLOCK_RETURN);
	SSVAL(pdata,2,0); /* No fnum. */
	SIVAL(pdata,4,info); /* Was directory created. */

	switch (info_level_return) {
		case SMB_QUERY_FILE_UNIX_BASIC:
			SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
			SSVAL(pdata,10,0); /* Padding. */
			store_file_unix_basic(conn, pdata + 12, fsp,
					      &smb_fname->st);
			break;
		case SMB_QUERY_FILE_UNIX_INFO2:
			SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
			SSVAL(pdata,10,0); /* Padding. */
			store_file_unix_basic_info2(conn, pdata + 12, fsp,
						    &smb_fname->st);
			break;
		default:
			SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
			SSVAL(pdata,10,0); /* Padding. */
			break;
	}

	return status;
}

Project: samba
File: trans2.c

static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
{
	unsigned int ace_count = 0;
	int entry_id = SMB_ACL_FIRST_ENTRY;
	SMB_ACL_ENTRY_T entry;

	while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
		/* get_next... */
		if (entry_id == SMB_ACL_FIRST_ENTRY) {
			entry_id = SMB_ACL_NEXT_ENTRY;
		}
		ace_count++;
	}
	return ace_count;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
					      struct smb_request *req,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname,
					bool fail_after_createfile)
{
	off_t size;

	if (total_data < 8) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	size = IVAL(pdata,0);
	size |= (((off_t)IVAL(pdata,4)) << 32);
	DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
		  "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
		  (double)size));

	return smb_set_file_size(conn, req,
				fsp,
				smb_fname,
				&smb_fname->st,
				size,
				fail_after_createfile);
}

Project: samba
File: trans2.c

static NTSTATUS smb_info_set_ea(connection_struct *conn,
				const char *pdata,
				int total_data,
				files_struct *fsp,
				struct smb_filename *smb_fname)
{
	struct ea_list *ea_list = NULL;
	TALLOC_CTX *ctx = NULL;
	NTSTATUS status = NT_STATUS_OK;

	if (total_data < 10) {

		/* OS/2 workplace shell seems to send SET_EA requests of "null"
		   length. They seem to have no effect. Bug #3212. JRA */

		if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
			/* We're done. We only get EA info in this call. */
			return NT_STATUS_OK;
		}

		return NT_STATUS_INVALID_PARAMETER;
	}

	if (IVAL(pdata,0) > total_data) {
		DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
			IVAL(pdata,0), (unsigned int)total_data));
		return NT_STATUS_INVALID_PARAMETER;
	}

	ctx = talloc_tos();
	ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
	if (!ea_list) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp == NULL) {
		/*
		 * The only way fsp can be NULL here is if
		 * smb_fname points at a symlink and
		 * and we're in POSIX context.
		 * Ensure this is the case.
		 *
		 * In this case we cannot set the EA.
		 */
		SMB_ASSERT(smb_fname->flags & SMB_FILENAME_POSIX_PATH);
		return NT_STATUS_ACCESS_DENIED;
	}

	status = set_ea(conn, fsp, ea_list);

	return status;
}

Project: samba
File: trans2.c

static char *store_file_unix_basic(connection_struct *conn,
				char *pdata,
				files_struct *fsp,
				const SMB_STRUCT_STAT *psbuf)
{
	dev_t devno;

	DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
	DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));

	SOFF_T(pdata,0,get_file_size_stat(psbuf));             /* File size 64 Bit */
	pdata += 8;

	SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
	pdata += 8;

	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime);       /* Change Time 64 Bit */
	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime);     /* Last access time 64 Bit */
	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime);    /* Last modification time 64 Bit */
	pdata += 24;

	SIVAL(pdata,0,psbuf->st_ex_uid);               /* user id for the owner */
	SIVAL(pdata,4,0);
	pdata += 8;

	SIVAL(pdata,0,psbuf->st_ex_gid);               /* group id of owner */
	SIVAL(pdata,4,0);
	pdata += 8;

	SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
	pdata += 4;

	if (S_ISBLK(psbuf->st_ex_mode) || S_ISCHR(psbuf->st_ex_mode)) {
		devno = psbuf->st_ex_rdev;
	} else {
		devno = psbuf->st_ex_dev;
	}

	SIVAL(pdata,0,unix_dev_major(devno));   /* Major device number if type is device */
	SIVAL(pdata,4,0);
	pdata += 8;

	SIVAL(pdata,0,unix_dev_minor(devno));   /* Minor device number if type is device */
	SIVAL(pdata,4,0);
	pdata += 8;

	SINO_T_VAL(pdata, 0, psbuf->st_ex_ino);   /* inode number */
	pdata += 8;

	SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode));     /* Standard UNIX file permissions */
	SIVAL(pdata,4,0);
	pdata += 8;

	SIVAL(pdata,0,psbuf->st_ex_nlink);             /* number of hard links */
	SIVAL(pdata,4,0);
	pdata += 8;

	return pdata;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
					struct smb_request *req,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname)
{
	NTSTATUS status;
	uint32_t smb_fflags;
	uint32_t smb_fmask;

	if (total_data < 116) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* Start by setting all the fields that are common between UNIX_BASIC
	 * and UNIX_INFO2.
	 */
	status = smb_set_file_unix_basic(conn, req, pdata, total_data,
					 fsp, smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	smb_fflags = IVAL(pdata, 108);
	smb_fmask = IVAL(pdata, 112);

	/* NB: We should only attempt to alter the file flags if the client
	 * sends a non-zero mask.
	 */
	if (smb_fmask != 0) {
		int stat_fflags = 0;

		if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
					     smb_fmask, &stat_fflags)) {
			/* Client asked to alter a flag we don't understand. */
			return NT_STATUS_INVALID_PARAMETER;
		}

		if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
			DBG_WARNING("Can't change flags on symlink %s\n",
				smb_fname_str_dbg(smb_fname));
			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
		}
		if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
			return map_nt_error_from_unix(errno);
		}
	}

	/* XXX: need to add support for changing the create_time here. You
	 * can do this for paths on Darwin with setattrlist(2). The right way
	 * to hook this up is probably by extending the VFS utimes interface.
	 */

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS marshall_stream_info(unsigned int num_streams,
				     const struct stream_struct *streams,
				     char *data,
				     unsigned int max_data_bytes,
				     unsigned int *data_size)
{
	unsigned int i;
	unsigned int ofs = 0;

	if (max_data_bytes < 32) {
		return NT_STATUS_INFO_LENGTH_MISMATCH;
	}

	for (i = 0; i < num_streams; i++) {
		unsigned int next_offset;
		size_t namelen;
		smb_ucs2_t *namebuf;

		if (!push_ucs2_talloc(talloc_tos(), &namebuf,
				      streams[i].name, &namelen) ||
		    namelen <= 2)
		{
			return NT_STATUS_INVALID_PARAMETER;
		}

		/*
		 * name_buf is now null-terminated, we need to marshall as not
		 * terminated
		 */

		namelen -= 2;

		/*
		 * We cannot overflow ...
		 */
		if ((ofs + 24 + namelen) > max_data_bytes) {
			DEBUG(10, ("refusing to overflow reply at stream %u\n",
				i));
			TALLOC_FREE(namebuf);
			return STATUS_BUFFER_OVERFLOW;
		}

		SIVAL(data, ofs+4, namelen);
		SOFF_T(data, ofs+8, streams[i].size);
		SOFF_T(data, ofs+16, streams[i].alloc_size);
		memcpy(data+ofs+24, namebuf, namelen);
		TALLOC_FREE(namebuf);

		next_offset = ofs + 24 + namelen;

		if (i == num_streams-1) {
			SIVAL(data, ofs, 0);
		}
		else {
			unsigned int align = ndr_align_size(next_offset, 8);

			if ((next_offset + align) > max_data_bytes) {
				DEBUG(10, ("refusing to overflow align "
					"reply at stream %u\n",
					i));
				TALLOC_FREE(namebuf);
				return STATUS_BUFFER_OVERFLOW;
			}

			memset(data+next_offset, 0, align);
			next_offset += align;

			SIVAL(data, ofs, next_offset - ofs);
			ofs = next_offset;
		}

		ofs = next_offset;
	}

	DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));

	*data_size = ofs;

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_file_link_information(connection_struct *conn,
					    struct smb_request *req,
					    const char *pdata,
					    int total_data,
					    files_struct *fsp,
					    struct smb_filename *smb_fname_src)
{
	bool overwrite;
	uint32_t len;
	char *newname = NULL;
	struct smb_filename *smb_fname_dst = NULL;
	NTSTATUS status = NT_STATUS_OK;
	uint32_t ucf_flags = ucf_flags_from_smb_request(req);
	TALLOC_CTX *ctx = talloc_tos();

	if (!fsp) {
		return NT_STATUS_INVALID_HANDLE;
	}

	if (total_data < 20) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	overwrite = (CVAL(pdata,0) ? true : false);
	len = IVAL(pdata,16);

	if (len > (total_data - 20) || (len == 0)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
		srvstr_get_path_posix(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[20],
				len,
				STR_TERMINATE,
				&status);
		ucf_flags |= UCF_POSIX_PATHNAMES;
	} else {
		srvstr_get_path(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[20],
				len,
				STR_TERMINATE,
				&status);
	}
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	DEBUG(10,("smb_file_link_information: got name |%s|\n",
				newname));

	status = filename_convert(ctx,
				conn,
				newname,
				ucf_flags,
				0,
				&smb_fname_dst);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (fsp->base_fsp) {
		/* No stream names. */
		return NT_STATUS_NOT_SUPPORTED;
	}

	DEBUG(10,("smb_file_link_information: "
		  "SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
		  fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
		  smb_fname_str_dbg(smb_fname_dst)));
	status = hardlink_internals(ctx,
				conn,
				req,
				overwrite,
				fsp->fsp_name,
				smb_fname_dst);

	TALLOC_FREE(smb_fname_dst);
	return status;
}

Project: samba
File: trans2.c

static NTSTATUS smb_query_posix_acl(connection_struct *conn,
				struct smb_request *req,
				files_struct *fsp,
				struct smb_filename *smb_fname,
				char *pdata,
				unsigned int data_size_in,
				unsigned int *pdata_size_out)
{
	SMB_ACL_T file_acl = NULL;
	SMB_ACL_T def_acl = NULL;
	uint16_t num_file_acls = 0;
	uint16_t num_def_acls = 0;
	unsigned int size_needed = 0;
	NTSTATUS status;
	bool ok;
	bool close_fsp = false;

	/*
	 * Ensure we always operate on a file descriptor, not just
	 * the filename.
	 */
	if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
		uint32_t access_mask = SEC_STD_READ_CONTROL|
					FILE_READ_ATTRIBUTES|
					FILE_WRITE_ATTRIBUTES;

		status = get_posix_fsp(conn,
					req,
					smb_fname,
					access_mask,
					&fsp);

		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}
		close_fsp = true;
	}

	SMB_ASSERT(fsp != NULL);

	status = refuse_symlink_fsp(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		goto out;
	}

	file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
					talloc_tos());

	if (file_acl == NULL && no_acl_syscall_error(errno)) {
		DBG_INFO("ACLs not implemented on "
			"filesystem containing %s\n",
			fsp_str_dbg(fsp));
		status = NT_STATUS_NOT_IMPLEMENTED;
		goto out;
	}

	if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
		/*
		 * We can only have default POSIX ACLs on
		 * directories.
		 */
		if (!fsp->fsp_flags.is_directory) {
			DBG_INFO("Non-directory open %s\n",
				fsp_str_dbg(fsp));
			status = NT_STATUS_INVALID_HANDLE;
			goto out;
		}
		def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
					SMB_ACL_TYPE_DEFAULT,
					talloc_tos());
		def_acl = free_empty_sys_acl(conn, def_acl);
	}

	num_file_acls = count_acl_entries(conn, file_acl);
	num_def_acls = count_acl_entries(conn, def_acl);

	/* Wrap checks. */
	if (num_file_acls + num_def_acls < num_file_acls) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	size_needed = num_file_acls + num_def_acls;

	/*
	 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
	 * than UINT_MAX, so check by division.
	 */
	if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
	if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}
	size_needed += SMB_POSIX_ACL_HEADER_SIZE;

	if ( data_size_in < size_needed) {
		DBG_INFO("data_size too small (%u) need %u\n",
			data_size_in,
			size_needed);
		status = NT_STATUS_BUFFER_TOO_SMALL;
		goto out;
	}

	SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
	SSVAL(pdata,2,num_file_acls);
	SSVAL(pdata,4,num_def_acls);
	pdata += SMB_POSIX_ACL_HEADER_SIZE;

	ok = marshall_posix_acl(conn,
			pdata,
			&fsp->fsp_name->st,
			file_acl);
	if (!ok) {
		status = NT_STATUS_INTERNAL_ERROR;
		goto out;
	}
	pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);

	ok = marshall_posix_acl(conn,
			pdata,
			&fsp->fsp_name->st,
			def_acl);
	if (!ok) {
		status = NT_STATUS_INTERNAL_ERROR;
		goto out;
	}

	*pdata_size_out = size_needed;
	status = NT_STATUS_OK;

  out:

	if (close_fsp) {
		/*
		 * Ensure the stat struct in smb_fname is up to
		 * date. Structure copy.
		 */
		smb_fname->st = fsp->fsp_name->st;
		(void)close_file(req, fsp, NORMAL_CLOSE);
		fsp = NULL;
	}

	TALLOC_FREE(file_acl);
	TALLOC_FREE(def_acl);
	return status;
}

Project: samba
File: trans2.c

static bool exact_match(bool has_wild,
			bool case_sensitive,
			const char *str,
			const char *mask)
{
	if (mask[0] == '.' && mask[1] == 0) {
		return false;
	}

	if (has_wild) {
		return false;
	}

	if (case_sensitive) {
		return strcmp(str,mask)==0;
	} else {
		return strcasecmp_m(str,mask) == 0;
	}
}

Project: samba
File: trans2.c

NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
			 connection_struct *conn,
			 TALLOC_CTX *mem_ctx,
			 uint16_t info_level,
			 uint16_t flags2,
			 unsigned int max_data_bytes,
			 size_t *fixed_portion,
			 struct smb_filename *fname,
			 char **ppdata,
			 int *ret_data_len)
{
	const struct loadparm_substitution *lp_sub =
		loadparm_s3_global_substitution();
	char *pdata, *end_data;
	int data_len = 0;
	size_t len = 0;
	const char *vname = volume_label(talloc_tos(), SNUM(conn));
	int snum = SNUM(conn);
	const char *fstype = lp_fstype(SNUM(conn));
	const char *filename = NULL;
	const uint64_t bytes_per_sector = 512;
	uint32_t additional_flags = 0;
	struct smb_filename smb_fname;
	SMB_STRUCT_STAT st;
	NTSTATUS status = NT_STATUS_OK;
	uint64_t df_ret;

	if (fname == NULL || fname->base_name == NULL) {
		filename = ".";
	} else {
		filename = fname->base_name;
	}

	if (IS_IPC(conn)) {
		if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
			DEBUG(0,("smbd_do_qfsinfo: not an allowed "
				"info level (0x%x) on IPC$.\n",
				(unsigned int)info_level));
			return NT_STATUS_ACCESS_DENIED;
		}
	}

	DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));

	smb_fname = (struct smb_filename) {
		.base_name = discard_const_p(char, filename),
		.flags = fname ? fname->flags : 0,
		.twrp = fname ? fname->twrp : 0,
	};

	if(info_level != SMB_FS_QUOTA_INFORMATION
	   && SMB_VFS_STAT(conn, &smb_fname) != 0) {
		DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
		return map_nt_error_from_unix(errno);
	}

	st = smb_fname.st;

	if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	*ppdata = (char *)SMB_REALLOC(
		*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
	if (*ppdata == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	pdata = *ppdata;
	memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
	end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;

	*fixed_portion = 0;

	switch (info_level) {
		case SMB_INFO_ALLOCATION:
		{
			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
			data_len = 18;
			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
						&dfree, &dsize);
			if (df_ret == (uint64_t)-1) {
				return map_nt_error_from_unix(errno);
			}

			block_size = lp_block_size(snum);
			if (bsize < block_size) {
				uint64_t factor = block_size/bsize;
				bsize = block_size;
				dsize /= factor;
				dfree /= factor;
			}
			if (bsize > block_size) {
				uint64_t factor = bsize/block_size;
				bsize = block_size;
				dsize *= factor;
				dfree *= factor;
			}
			sectors_per_unit = bsize/bytes_per_sector;

			DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
				(unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));

			/*
			 * For large drives, return max values and not modulo.
			 */
			dsize = MIN(dsize, UINT32_MAX);
			dfree = MIN(dfree, UINT32_MAX);

			SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
			SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
			SIVAL(pdata,l1_cUnit,dsize);
			SIVAL(pdata,l1_cUnitAvail,dfree);
			SSVAL(pdata,l1_cbSector,bytes_per_sector);
			break;
		}

		case SMB_INFO_VOLUME:
			/* Return volume name */
			/* 
			 * Add volume serial number - hash of a combination of
			 * the called hostname and the service name.
			 */
			SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^ (str_checksum(get_local_machine_name())<<16) );
			/*
			 * Win2k3 and previous mess this up by sending a name length
			 * one byte short. I believe only older clients (OS/2 Win9x) use
			 * this call so try fixing this by adding a terminating null to
			 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
			 */
			status = srvstr_push(
				pdata, flags2,
				pdata+l2_vol_szVolLabel, vname,
				PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
				STR_NOALIGN|STR_TERMINATE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SCVAL(pdata,l2_vol_cch,len);
			data_len = l2_vol_szVolLabel + len;
			DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, name = %s\n",
				 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
				 (unsigned)len, vname));
			break;

		case SMB_QUERY_FS_ATTRIBUTE_INFO:
		case SMB_FS_ATTRIBUTE_INFORMATION:

			additional_flags = 0;
#if defined(HAVE_SYS_QUOTAS)
			additional_flags |= FILE_VOLUME_QUOTAS;
#endif

			if(lp_nt_acl_support(SNUM(conn))) {
				additional_flags |= FILE_PERSISTENT_ACLS;
			}

			/* Capabilities are filled in at connection time through STATVFS call */
			additional_flags |= conn->fs_capabilities;
			additional_flags |= lp_parm_int(conn->params->service,
							"share", "fake_fscaps",
							0);

			SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
				FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
				additional_flags); /* FS ATTRIBUTES */

			SIVAL(pdata,4,255); /* Max filename component length */
			/* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
				and will think we can't do long filenames */
			status = srvstr_push(pdata, flags2, pdata+12, fstype,
					  PTR_DIFF(end_data, pdata+12),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SIVAL(pdata,8,len);
			data_len = 12 + len;
			if (max_data_bytes >= 16 && data_len > max_data_bytes) {
				/* the client only requested a portion of the
				   file system name */
				data_len = max_data_bytes;
				status = STATUS_BUFFER_OVERFLOW;
			}
			*fixed_portion = 16;
			break;

		case SMB_QUERY_FS_LABEL_INFO:
		case SMB_FS_LABEL_INFORMATION:
			status = srvstr_push(pdata, flags2, pdata+4, vname,
					  PTR_DIFF(end_data, pdata+4), 0, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			data_len = 4 + len;
			SIVAL(pdata,0,len);
			break;

		case SMB_QUERY_FS_VOLUME_INFO:      
		case SMB_FS_VOLUME_INFORMATION:

			/* 
			 * Add volume serial number - hash of a combination of
			 * the called hostname and the service name.
			 */
			SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^
				(str_checksum(get_local_machine_name())<<16));

			/* Max label len is 32 characters. */
			status = srvstr_push(pdata, flags2, pdata+18, vname,
					  PTR_DIFF(end_data, pdata+18),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SIVAL(pdata,12,len);
			data_len = 18+len;

			DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
				(int)strlen(vname),vname,
				lp_servicename(talloc_tos(), lp_sub, snum)));
			if (max_data_bytes >= 24 && data_len > max_data_bytes) {
				/* the client only requested a portion of the
				   volume label */
				data_len = max_data_bytes;
				status = STATUS_BUFFER_OVERFLOW;
			}
			*fixed_portion = 24;
			break;

		case SMB_QUERY_FS_SIZE_INFO:
		case SMB_FS_SIZE_INFORMATION:
		{
			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
			data_len = 24;
			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
						&dfree, &dsize);
			if (df_ret == (uint64_t)-1) {
				return map_nt_error_from_unix(errno);
			}
			block_size = lp_block_size(snum);
			if (bsize < block_size) {
				uint64_t factor = block_size/bsize;
				bsize = block_size;
				dsize /= factor;
				dfree /= factor;
			}
			if (bsize > block_size) {
				uint64_t factor = bsize/block_size;
				bsize = block_size;
				dsize *= factor;
				dfree *= factor;
			}
			sectors_per_unit = bsize/bytes_per_sector;
			DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
				(unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
			SBIG_UINT(pdata,0,dsize);
			SBIG_UINT(pdata,8,dfree);
			SIVAL(pdata,16,sectors_per_unit);
			SIVAL(pdata,20,bytes_per_sector);
			*fixed_portion = 24;
			break;
		}

		case SMB_FS_FULL_SIZE_INFORMATION:
		{
			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
			data_len = 32;
			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
						&dfree, &dsize);
			if (df_ret == (uint64_t)-1) {
				return map_nt_error_from_unix(errno);
			}
			block_size = lp_block_size(snum);
			if (bsize < block_size) {
				uint64_t factor = block_size/bsize;
				bsize = block_size;
				dsize /= factor;
				dfree /= factor;
			}
			if (bsize > block_size) {
				uint64_t factor = bsize/block_size;
				bsize = block_size;
				dsize *= factor;
				dfree *= factor;
			}
			sectors_per_unit = bsize/bytes_per_sector;
			DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
				(unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
			SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
			SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
			SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
			SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
			SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
			*fixed_portion = 32;
			break;
		}

		case SMB_QUERY_FS_DEVICE_INFO:
		case SMB_FS_DEVICE_INFORMATION:
		{
			uint32_t characteristics = FILE_DEVICE_IS_MOUNTED;

			if (!CAN_WRITE(conn)) {
				characteristics |= FILE_READ_ONLY_DEVICE;
			}
			data_len = 8;
			SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
			SIVAL(pdata,4,characteristics);
			*fixed_portion = 8;
			break;
		}

#ifdef HAVE_SYS_QUOTAS
		case SMB_FS_QUOTA_INFORMATION:
		/* 
		 * what we have to send --metze:
		 *
		 * Unknown1: 		24 NULL bytes
		 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
		 * Hard Quota Limit:	8 bytes seems like uint64_t or so
		 * Quota Flags:		2 byte :
		 * Unknown3:		6 NULL bytes
		 *
		 * 48 bytes total
		 * 
		 * details for Quota Flags:
		 * 
		 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
		 * 0x0010 Log Warn:  log if the user exceeds his Soft Quota
		 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
		 * 0x0001 Enable Quotas: enable quota for this fs
		 *
		 */
		{
			/* we need to fake up a fsp here,
			 * because its not send in this call
			 */
			files_struct fsp;
			SMB_NTQUOTA_STRUCT quotas;

			ZERO_STRUCT(fsp);
			ZERO_STRUCT(quotas);

			fsp.conn = conn;
			fsp.fnum = FNUM_FIELD_INVALID;

			/* access check */
			if (get_current_uid(conn) != 0) {
				DEBUG(0,("get_user_quota: access_denied "
					 "service [%s] user [%s]\n",
					 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
					 conn->session_info->unix_info->unix_name));
				return NT_STATUS_ACCESS_DENIED;
			}

			status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE,
						 NULL, &quotas);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
				return status;
			}

			data_len = 48;

			DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
				  lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));

			/* Unknown1 24 NULL bytes*/
			SBIG_UINT(pdata,0,(uint64_t)0);
			SBIG_UINT(pdata,8,(uint64_t)0);
			SBIG_UINT(pdata,16,(uint64_t)0);

			/* Default Soft Quota 8 bytes */
			SBIG_UINT(pdata,24,quotas.softlim);

			/* Default Hard Quota 8 bytes */
			SBIG_UINT(pdata,32,quotas.hardlim);

			/* Quota flag 2 bytes */
			SSVAL(pdata,40,quotas.qflags);

			/* Unknown3 6 NULL bytes */
			SSVAL(pdata,42,0);
			SIVAL(pdata,44,0);

			break;
		}
#endif /* HAVE_SYS_QUOTAS */
		case SMB_FS_OBJECTID_INFORMATION:
		{
			unsigned char objid[16];
			struct smb_extended_info extended_info;
			memcpy(pdata,create_volume_objectid(conn, objid),16);
			samba_extended_info_version (&extended_info);
			SIVAL(pdata,16,extended_info.samba_magic);
			SIVAL(pdata,20,extended_info.samba_version);
			SIVAL(pdata,24,extended_info.samba_subversion);
			SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
			memcpy(pdata+36,extended_info.samba_version_string,28);
			data_len = 64;
			break;
		}

		case SMB_FS_SECTOR_SIZE_INFORMATION:
		{
			data_len = 28;
			/*
			 * These values match a physical Windows Server 2012
			 * share backed by NTFS atop spinning rust.
			 */
			DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:"));
			/* logical_bytes_per_sector */
			SIVAL(pdata, 0, bytes_per_sector);
			/* phys_bytes_per_sector_atomic */
			SIVAL(pdata, 4, bytes_per_sector);
			/* phys_bytes_per_sector_perf */
			SIVAL(pdata, 8, bytes_per_sector);
			/* fs_effective_phys_bytes_per_sector_atomic */
			SIVAL(pdata, 12, bytes_per_sector);
			/* flags */
			SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE
				| SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
			/* byte_off_sector_align */
			SIVAL(pdata, 20, 0);
			/* byte_off_partition_align */
			SIVAL(pdata, 24, 0);
			*fixed_portion = 28;
			break;
		}


		/*
		 * Query the version and capabilities of the CIFS UNIX extensions
		 * in use.
		 */

		case SMB_QUERY_CIFS_UNIX_INFO:
		{
			bool large_write = lp_min_receive_file_size() &&
					!srv_is_signing_active(xconn);
			bool large_read = !srv_is_signing_active(xconn);
			int encrypt_caps = 0;

			if (!lp_unix_extensions()) {
				return NT_STATUS_INVALID_LEVEL;
			}

			switch (conn->encrypt_level) {
			case SMB_SIGNING_OFF:
				encrypt_caps = 0;
				break;
			case SMB_SIGNING_DESIRED:
			case SMB_SIGNING_IF_REQUIRED:
			case SMB_SIGNING_DEFAULT:
				encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
				break;
			case SMB_SIGNING_REQUIRED:
				encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
						CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
				large_write = false;
				large_read = false;
				break;
			}

			data_len = 12;
			SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
			SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);

			/* We have POSIX ACLs, pathname, encryption, 
			 * large read/write, and locking capability. */

			SBIG_UINT(pdata,4,((uint64_t)(
					CIFS_UNIX_POSIX_ACLS_CAP|
					CIFS_UNIX_POSIX_PATHNAMES_CAP|
					CIFS_UNIX_FCNTL_LOCKS_CAP|
					CIFS_UNIX_EXTATTR_CAP|
					CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
					encrypt_caps|
					(large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
					(large_write ?
					CIFS_UNIX_LARGE_WRITE_CAP : 0))));
			break;
		}

		case SMB_QUERY_POSIX_FS_INFO:
		{
			int rc;
			vfs_statvfs_struct svfs;

			if (!lp_unix_extensions()) {
				return NT_STATUS_INVALID_LEVEL;
			}

			rc = SMB_VFS_STATVFS(conn, &smb_fname, &svfs);

			if (!rc) {
				data_len = 56;
				SIVAL(pdata,0,svfs.OptimalTransferSize);
				SIVAL(pdata,4,svfs.BlockSize);
				SBIG_UINT(pdata,8,svfs.TotalBlocks);
				SBIG_UINT(pdata,16,svfs.BlocksAvail);
				SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
				SBIG_UINT(pdata,32,svfs.TotalFileNodes);
				SBIG_UINT(pdata,40,svfs.FreeFileNodes);
				SBIG_UINT(pdata,48,svfs.FsIdentifier);
				DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
#ifdef EOPNOTSUPP
			} else if (rc == EOPNOTSUPP) {
				return NT_STATUS_INVALID_LEVEL;
#endif /* EOPNOTSUPP */
			} else {
				DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
				return NT_STATUS_DOS(ERRSRV, ERRerror);
			}
			break;
		}

		case SMB_QUERY_POSIX_WHOAMI:
		{
			uint32_t flags = 0;
			uint32_t sid_bytes;
			int i;

			if (!lp_unix_extensions()) {
				return NT_STATUS_INVALID_LEVEL;
			}

			if (max_data_bytes < 40) {
				return NT_STATUS_BUFFER_TOO_SMALL;
			}

			if (security_session_user_level(conn->session_info, NULL) < SECURITY_USER) {
				flags |= SMB_WHOAMI_GUEST;
			}

			/* NOTE: 8 bytes for UID/GID, irrespective of native
			 * platform size. This matches
			 * SMB_QUERY_FILE_UNIX_BASIC and friends.
			 */
			data_len = 4 /* flags */
			    + 4 /* flag mask */
			    + 8 /* uid */
			    + 8 /* gid */
			    + 4 /* ngroups */
			    + 4 /* num_sids */
			    + 4 /* SID bytes */
			    + 4 /* pad/reserved */
			    + (conn->session_info->unix_token->ngroups * 8)
				/* groups list */
			    + (conn->session_info->security_token->num_sids *
				    SID_MAX_SIZE)
				/* SID list */;

			SIVAL(pdata, 0, flags);
			SIVAL(pdata, 4, SMB_WHOAMI_MASK);
			SBIG_UINT(pdata, 8,
				  (uint64_t)conn->session_info->unix_token->uid);
			SBIG_UINT(pdata, 16,
				  (uint64_t)conn->session_info->unix_token->gid);


			if (data_len >= max_data_bytes) {
				/* Potential overflow, skip the GIDs and SIDs. */

				SIVAL(pdata, 24, 0); /* num_groups */
				SIVAL(pdata, 28, 0); /* num_sids */
				SIVAL(pdata, 32, 0); /* num_sid_bytes */
				SIVAL(pdata, 36, 0); /* reserved */

				data_len = 40;
				break;
			}

			SIVAL(pdata, 24, conn->session_info->unix_token->ngroups);
			SIVAL(pdata, 28, conn->session_info->security_token->num_sids);

			/* We walk the SID list twice, but this call is fairly
			 * infrequent, and I don't expect that it's performance
			 * sensitive -- jpeach
			 */
			for (i = 0, sid_bytes = 0;
			     i < conn->session_info->security_token->num_sids; ++i) {
				sid_bytes += ndr_size_dom_sid(
					&conn->session_info->security_token->sids[i],
					0);
			}

			/* SID list byte count */
			SIVAL(pdata, 32, sid_bytes);

			/* 4 bytes pad/reserved - must be zero */
			SIVAL(pdata, 36, 0);
			data_len = 40;

			/* GID list */
			for (i = 0; i < conn->session_info->unix_token->ngroups; ++i) {
				SBIG_UINT(pdata, data_len,
					  (uint64_t)conn->session_info->unix_token->groups[i]);
				data_len += 8;
			}

			/* SID list */
			for (i = 0;
			    i < conn->session_info->security_token->num_sids; ++i) {
				int sid_len = ndr_size_dom_sid(
					&conn->session_info->security_token->sids[i],
					0);

				sid_linearize((uint8_t *)(pdata + data_len),
					      sid_len,
				    &conn->session_info->security_token->sids[i]);
				data_len += sid_len;
			}

			break;
		}

		case SMB_MAC_QUERY_FS_INFO:
			/*
			 * Thursby MAC extension... ONLY on NTFS filesystems
			 * once we do streams then we don't need this
			 */
			if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
				data_len = 88;
				SIVAL(pdata,84,0x100); /* Don't support mac... */
				break;
			}

			FALL_THROUGH;
		default:
			return NT_STATUS_INVALID_LEVEL;
	}

	*ret_data_len = data_len;
	return status;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
				     struct files_struct *fsp,
				     uint32_t dosmode)
{
	struct files_struct *dos_fsp = NULL;
	uint32_t current_dosmode;
	int ret;

	if (!VALID_STAT(fsp->fsp_name->st)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	dos_fsp = fsp->base_fsp != NULL ? fsp->base_fsp : fsp;

	if (dosmode != 0) {
		if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
			dosmode |= FILE_ATTRIBUTE_DIRECTORY;
		} else {
			dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
		}
	}

	DBG_DEBUG("dosmode: 0x%" PRIx32 "\n", dosmode);

	/* check the mode isn't different, before changing it */
	if (dosmode == 0) {
		return NT_STATUS_OK;
	}
	current_dosmode = fdos_mode(dos_fsp);
	if (dosmode == current_dosmode) {
		return NT_STATUS_OK;
	}

	DBG_DEBUG("file %s : setting dos mode 0x%" PRIx32 "\n",
		  fsp_str_dbg(dos_fsp), dosmode);

	ret = file_set_dosmode(conn, dos_fsp->fsp_name, dosmode, NULL, false);
	if (ret != 0) {
		DBG_WARNING("file_set_dosmode of %s failed: %s\n",
			    fsp_str_dbg(dos_fsp), strerror(errno));
		return map_nt_error_from_unix(errno);
	}

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname)
{
	/* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
	struct smb_file_time ft;
	uint32_t dosmode = 0;
	NTSTATUS status = NT_STATUS_OK;

	init_smb_file_time(&ft);

	if (total_data < 36) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp == NULL) {
		return NT_STATUS_INVALID_HANDLE;
	}

	status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* Set the attributes */
	dosmode = IVAL(pdata,32);
	status = smb_set_file_dosmode(conn, fsp, dosmode);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* create time */
	ft.create_time = pull_long_date_full_timespec(pdata);

	/* access time */
	ft.atime = pull_long_date_full_timespec(pdata+8);

	/* write time. */
	ft.mtime = pull_long_date_full_timespec(pdata+16);

	/* change time. */
	ft.ctime = pull_long_date_full_timespec(pdata+24);

	DEBUG(10, ("smb_set_file_basic_info: file %s\n",
		   smb_fname_str_dbg(smb_fname)));

	status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (fsp->fsp_flags.modified) {
		trigger_write_time_update_immediate(fsp);
	}
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static void call_trans2ioctl(connection_struct *conn,
			     struct smb_request *req,
			     char **pparams, int total_params,
			     char **ppdata, int total_data,
			     unsigned int max_data_bytes)
{
	const struct loadparm_substitution *lp_sub =
		loadparm_s3_global_substitution();
	char *pdata = *ppdata;
	files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
	NTSTATUS status;
	size_t len = 0;

	/* check for an invalid fid before proceeding */

	if (!fsp) {
		reply_nterror(req, NT_STATUS_INVALID_HANDLE);
		return;
	}

	if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
	    && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
		*ppdata = (char *)SMB_REALLOC(*ppdata, 32);
		if (*ppdata == NULL) {
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		pdata = *ppdata;

		/* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
			CAN ACCEPT THIS IN UNICODE. JRA. */

		/* Job number */
		SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));

		status = srvstr_push(pdata, req->flags2, pdata + 2,
			    lp_netbios_name(), 15,
			    STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, status);
			return;
		}
		status = srvstr_push(pdata, req->flags2, pdata+18,
			    lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
			    STR_ASCII|STR_TERMINATE, &len); /* Service name */
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, status);
			return;
		}
		send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
				    max_data_bytes);
		return;
	}

	DEBUG(2,("Unknown TRANS2_IOCTL\n"));
	reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
}

Project: samba
File: trans2.c

NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
				files_struct *fsp,
				char ***pnames,
				size_t *pnum_names)
{
	char smallbuf[1024];
	/* Get a list of all xattrs. Max namesize is 64k. */
	size_t ea_namelist_size = 1024;
	char *ea_namelist = smallbuf;
	char *to_free = NULL;

	char *p;
	char **names;
	size_t num_names;
	ssize_t sizeret = -1;
	NTSTATUS status;

	if (pnames) {
		*pnames = NULL;
	}
	*pnum_names = 0;

	if (fsp == NULL) {
		/*
		 * Callers may pass fsp == NULL when passing smb_fname->fsp of a
		 * symlink. This is ok, handle it here, by just return no EA's
		 * on a symlink.
		 */
		return NT_STATUS_OK;
	}

	/* should be the case that fsp != NULL */
	SMB_ASSERT(fsp != NULL);

	sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
				     ea_namelist_size);

	if ((sizeret == -1) && (errno == ERANGE)) {
		ea_namelist_size = 65536;
		ea_namelist = talloc_array(mem_ctx, char, ea_namelist_size);
		if (ea_namelist == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
		to_free = ea_namelist;

		sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
					     ea_namelist_size);
	}

	if (sizeret == -1) {
		status = map_nt_error_from_unix(errno);
		TALLOC_FREE(to_free);
		return status;
	}

	DBG_DEBUG("ea_namelist size = %zd\n", sizeret);

	if (sizeret == 0) {
		TALLOC_FREE(to_free);
		return NT_STATUS_OK;
	}

	/*
	 * Ensure the result is 0-terminated
	 */

	if (ea_namelist[sizeret-1] != '\0') {
		TALLOC_FREE(to_free);
		return NT_STATUS_INTERNAL_ERROR;
	}

	/*
	 * count the names
	 */
	num_names = 0;

	for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
		num_names += 1;
	}

	*pnum_names = num_names;

	if (pnames == NULL) {
		TALLOC_FREE(to_free);
		return NT_STATUS_OK;
	}

	names = talloc_array(mem_ctx, char *, num_names);
	if (names == NULL) {
		DEBUG(0, ("talloc failed\n"));
		TALLOC_FREE(to_free);
		return NT_STATUS_NO_MEMORY;
	}

	if (ea_namelist == smallbuf) {
		ea_namelist = talloc_memdup(names, smallbuf, sizeret);
		if (ea_namelist == NULL) {
			TALLOC_FREE(names);
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		talloc_steal(names, ea_namelist);

		ea_namelist = talloc_realloc(names, ea_namelist, char,
					     sizeret);
		if (ea_namelist == NULL) {
			TALLOC_FREE(names);
			return NT_STATUS_NO_MEMORY;
		}
	}

	num_names = 0;

	for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
		names[num_names++] = p;
	}

	*pnames = names;

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
				files_struct *fsp,
				size_t *pea_total_len,
				struct ea_list **ea_list)
{
	/* Get a list of all xattrs. Max namesize is 64k. */
	size_t i, num_names;
	char **names;
	struct ea_list *ea_list_head = NULL;
	bool posix_pathnames = false;
	NTSTATUS status;

	*pea_total_len = 0;
	*ea_list = NULL;

	/* symlink */
	if (fsp == NULL) {
		return NT_STATUS_OK;
	}

	if (!lp_ea_support(SNUM(fsp->conn))) {
		return NT_STATUS_OK;
	}

	if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);

	status = get_ea_names_from_fsp(talloc_tos(),
				fsp,
				&names,
				&num_names);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (num_names == 0) {
		return NT_STATUS_OK;
	}

	for (i=0; i<num_names; i++) {
		struct ea_list *listp;
		fstring dos_ea_name;

		if (strnequal(names[i], "system.", 7)
		    || samba_private_attr_name(names[i]))
			continue;

		/*
		 * Filter out any underlying POSIX EA names
		 * that a Windows client can't handle.
		 */
		if (!posix_pathnames &&
				is_invalid_windows_ea_name(names[i])) {
			continue;
		}

		listp = talloc(mem_ctx, struct ea_list);
		if (listp == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		status = get_ea_value_fsp(listp,
					  fsp,
					  names[i],
					  &listp->ea);

		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(listp);
			return status;
		}

		if (listp->ea.value.length == 0) {
			/*
			 * We can never return a zero length EA.
			 * Windows reports the EA's as corrupted.
			 */
			TALLOC_FREE(listp);
			continue;
		} else if (listp->ea.value.length > 65536) {
			/*
			 * SMB clients may report error with file
			 * if large EA is presented to them.
			 */
			DBG_ERR("EA [%s] on file [%s] exceeds "
				"maximum permitted EA size of 64KiB: %zu\n.",
				listp->ea.name, fsp_str_dbg(fsp),
				listp->ea.value.length);
			TALLOC_FREE(listp);
			continue;
		}

		push_ascii_fstring(dos_ea_name, listp->ea.name);

		*pea_total_len +=
			4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;

		DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
			  "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
			  (unsigned int)listp->ea.value.length));

		DLIST_ADD_END(ea_list_head, listp);

	}

	/* Add on 4 for total length. */
	if (*pea_total_len) {
		*pea_total_len += 4;
	}

	DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
		   (unsigned int)*pea_total_len));

	*ea_list = ea_list_head;
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
				const uint32_t smb_fflags,
				const uint32_t smb_fmask,
				int *stat_fflags)
{
	uint32_t max_fmask = 0;
	int i;

	*stat_fflags = psbuf->st_ex_flags;

	/* For each flags requested in smb_fmask, check the state of the
	 * corresponding flag in smb_fflags and set or clear the matching
	 * stat flag.
	 */

	for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
	    max_fmask |= info2_flags_map[i].smb_fflag;
	    if (smb_fmask & info2_flags_map[i].smb_fflag) {
		    if (smb_fflags & info2_flags_map[i].smb_fflag) {
			    *stat_fflags |= info2_flags_map[i].stat_fflag;
		    } else {
			    *stat_fflags &= ~info2_flags_map[i].stat_fflag;
		    }
	    }
	}

	/* If smb_fmask is asking to set any bits that are not supported by
	 * our flag mappings, we should fail.
	 */
	if ((smb_fmask & max_fmask) != smb_fmask) {
		return False;
	}

	return True;
}

Project: samba
File: trans2.c

NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
			       TALLOC_CTX *mem_ctx,
			       struct smb_request *req,
			       uint16_t info_level,
			       files_struct *fsp,
			       struct smb_filename *smb_fname,
			       bool delete_pending,
			       struct timespec write_time_ts,
			       struct ea_list *ea_list,
			       int lock_data_count,
			       char *lock_data,
			       uint16_t flags2,
			       unsigned int max_data_bytes,
			       size_t *fixed_portion,
			       char **ppdata,
			       unsigned int *pdata_size)
{
	char *pdata = *ppdata;
	char *dstart, *dend;
	unsigned int data_size;
	struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
	time_t create_time, mtime, atime, c_time;
	SMB_STRUCT_STAT *psbuf = NULL;
	char *p;
	char *base_name;
	char *dos_fname;
	int mode;
	int nlink;
	NTSTATUS status;
	uint64_t file_size = 0;
	uint64_t pos = 0;
	uint64_t allocation_size = 0;
	uint64_t file_id = 0;
	uint32_t access_mask = 0;
	size_t len = 0;

	if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
		return NT_STATUS_INVALID_LEVEL;
	}

	DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
		 smb_fname_str_dbg(smb_fname),
		 fsp_fnum_dbg(fsp),
		 info_level, max_data_bytes));

	/*
	 * In case of querying a symlink in POSIX context,
	 * fsp will be NULL. fdos_mode() deals with it.
	 */
	if (fsp != NULL) {
		smb_fname = fsp->fsp_name;
	}
	mode = fdos_mode(fsp);
	psbuf = &smb_fname->st;

	nlink = psbuf->st_ex_nlink;

	if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
		nlink = 1;
	}

	if ((nlink > 0) && delete_pending) {
		nlink -= 1;
	}

	if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
	*ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
	if (*ppdata == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	pdata = *ppdata;
	dstart = pdata;
	dend = dstart + data_size - 1;

	if (!is_omit_timespec(&write_time_ts) &&
	    !INFO_LEVEL_IS_UNIX(info_level))
	{
		update_stat_ex_mtime(psbuf, write_time_ts);
	}

	create_time_ts = get_create_timespec(conn, fsp, smb_fname);
	mtime_ts = psbuf->st_ex_mtime;
	atime_ts = psbuf->st_ex_atime;
	ctime_ts = get_change_timespec(conn, fsp, smb_fname);

	if (lp_dos_filetime_resolution(SNUM(conn))) {
		dos_filetime_timespec(&create_time_ts);
		dos_filetime_timespec(&mtime_ts);
		dos_filetime_timespec(&atime_ts);
		dos_filetime_timespec(&ctime_ts);
	}

	create_time = convert_timespec_to_time_t(create_time_ts);
	mtime = convert_timespec_to_time_t(mtime_ts);
	atime = convert_timespec_to_time_t(atime_ts);
	c_time = convert_timespec_to_time_t(ctime_ts);

	p = strrchr_m(smb_fname->base_name,'/');
	if (!p)
		base_name = smb_fname->base_name;
	else
		base_name = p+1;

	/* NT expects the name to be in an exact form of the *full*
	   filename. See the trans2 torture test */
	if (ISDOT(base_name)) {
		dos_fname = talloc_strdup(mem_ctx, "\\");
		if (!dos_fname) {
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		dos_fname = talloc_asprintf(mem_ctx,
				"\\%s",
				smb_fname->base_name);
		if (!dos_fname) {
			return NT_STATUS_NO_MEMORY;
		}
		if (is_ntfs_stream_smb_fname(smb_fname)) {
			dos_fname = talloc_asprintf(dos_fname, "%s",
						    smb_fname->stream_name);
			if (!dos_fname) {
				return NT_STATUS_NO_MEMORY;
			}
		}

		string_replace(dos_fname, '/', '\\');
	}

	allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);

	if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
		/* Do we have this path open ? */
		files_struct *fsp1;
		struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
		fsp1 = file_find_di_first(conn->sconn, fileid, true);
		if (fsp1 && fsp1->initial_allocation_size) {
			allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
		}
	}

	if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
		file_size = get_file_size_stat(psbuf);
	}

	if (fsp) {
		pos = fh_get_position_information(fsp->fh);
	}

	if (fsp) {
		access_mask = fsp->access_mask;
	} else {
		/* GENERIC_EXECUTE mapping from Windows */
		access_mask = 0x12019F;
	}

	/* This should be an index number - looks like
	   dev/ino to me :-)

	   I think this causes us to fail the IFSKIT
	   BasicFileInformationTest. -tpot */
	file_id = SMB_VFS_FS_FILE_ID(conn, psbuf);

	*fixed_portion = 0;

	switch (info_level) {
		case SMB_INFO_STANDARD:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
			data_size = 22;
			srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
			srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
			srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
			SIVAL(pdata,l1_cbFile,(uint32_t)file_size);
			SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size);
			SSVAL(pdata,l1_attrFile,mode);
			break;

		case SMB_INFO_QUERY_EA_SIZE:
		{
			unsigned int ea_size =
			    estimate_ea_size(smb_fname->fsp);
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
			data_size = 26;
			srv_put_dos_date2(pdata,0,create_time);
			srv_put_dos_date2(pdata,4,atime);
			srv_put_dos_date2(pdata,8,mtime); /* write time */
			SIVAL(pdata,12,(uint32_t)file_size);
			SIVAL(pdata,16,(uint32_t)allocation_size);
			SSVAL(pdata,20,mode);
			SIVAL(pdata,22,ea_size);
			break;
		}

		case SMB_INFO_IS_NAME_VALID:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
			if (fsp) {
				/* os/2 needs this ? really ?*/
				return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
			}
			/* This is only reached for qpathinfo */
			data_size = 0;
			break;

		case SMB_INFO_QUERY_EAS_FROM_LIST:
		{
			size_t total_ea_len = 0;
			struct ea_list *ea_file_list = NULL;
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));

			status =
			    get_ea_list_from_fsp(mem_ctx,
						  smb_fname->fsp,
						  &total_ea_len, &ea_file_list);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}

			ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);

			if (!ea_list || (total_ea_len > data_size)) {
				data_size = 4;
				SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
				break;
			}

			data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
			break;
		}

		case SMB_INFO_QUERY_ALL_EAS:
		{
			/* We have data_size bytes to put EA's into. */
			size_t total_ea_len = 0;
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));

			status = get_ea_list_from_fsp(mem_ctx,
							smb_fname->fsp,
							&total_ea_len, &ea_list);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}

			if (!ea_list || (total_ea_len > data_size)) {
				data_size = 4;
				SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
				break;
			}

			data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
			break;
		}

		case SMB2_FILE_FULL_EA_INFORMATION:
		{
			/* We have data_size bytes to put EA's into. */
			size_t total_ea_len = 0;
			struct ea_list *ea_file_list = NULL;

			DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));

			/*TODO: add filtering and index handling */

			status  =
				get_ea_list_from_fsp(mem_ctx,
						  smb_fname->fsp,
						  &total_ea_len, &ea_file_list);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			if (!ea_file_list) {
				return NT_STATUS_NO_EAS_ON_FILE;
			}

			status = fill_ea_chained_buffer(mem_ctx,
							pdata,
							data_size,
							&data_size,
							conn, ea_file_list);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			break;
		}

		case SMB_FILE_BASIC_INFORMATION:
		case SMB_QUERY_FILE_BASIC_INFO:

			if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
				DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
				data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
			} else {
				DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
				data_size = 40;
				SIVAL(pdata,36,0);
			}
			put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
			put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
			SIVAL(pdata,32,mode);

			DEBUG(5,("SMB_QFBI - "));
			DEBUG(5,("create: %s ", ctime(&create_time)));
			DEBUG(5,("access: %s ", ctime(&atime)));
			DEBUG(5,("write: %s ", ctime(&mtime)));
			DEBUG(5,("change: %s ", ctime(&c_time)));
			DEBUG(5,("mode: %x\n", mode));
			*fixed_portion = data_size;
			break;

		case SMB_FILE_STANDARD_INFORMATION:
		case SMB_QUERY_FILE_STANDARD_INFO:

			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
			data_size = 24;
			SOFF_T(pdata,0,allocation_size);
			SOFF_T(pdata,8,file_size);
			SIVAL(pdata,16,nlink);
			SCVAL(pdata,20,delete_pending?1:0);
			SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
			SSVAL(pdata,22,0); /* Padding. */
			*fixed_portion = 24;
			break;

		case SMB_FILE_EA_INFORMATION:
		case SMB_QUERY_FILE_EA_INFO:
		{
			unsigned int ea_size =
			    estimate_ea_size(smb_fname->fsp);
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
			data_size = 4;
			*fixed_portion = 4;
			SIVAL(pdata,0,ea_size);
			break;
		}

		/* Get the 8.3 name - used if NT SMB was negotiated. */
		case SMB_QUERY_FILE_ALT_NAME_INFO:
		case SMB_FILE_ALTERNATE_NAME_INFORMATION:
		{
			char mangled_name[13];
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
			if (!name_to_8_3(base_name,mangled_name,
						True,conn->params)) {
				return NT_STATUS_NO_MEMORY;
			}
			status = srvstr_push(dstart, flags2,
					  pdata+4, mangled_name,
					  PTR_DIFF(dend, pdata+4),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			data_size = 4 + len;
			SIVAL(pdata,0,len);
			*fixed_portion = 8;
			break;
		}

		case SMB_QUERY_FILE_NAME_INFO:
		{
			/*
			  this must be *exactly* right for ACLs on mapped drives to work
			 */
			status = srvstr_push(dstart, flags2,
					  pdata+4, dos_fname,
					  PTR_DIFF(dend, pdata+4),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
			data_size = 4 + len;
			SIVAL(pdata,0,len);
			break;
		}

		case SMB_FILE_NORMALIZED_NAME_INFORMATION:
		{
			char *nfname = NULL;

			if (fsp == NULL || !fsp->conn->sconn->using_smb2) {
				return NT_STATUS_INVALID_LEVEL;
			}

			nfname = talloc_strdup(mem_ctx, smb_fname->base_name);
			if (nfname == NULL) {
				return NT_STATUS_NO_MEMORY;
			}

			if (ISDOT(nfname)) {
				nfname[0] = '\0';
			}
			string_replace(nfname, '/', '\\');

			if (smb_fname->stream_name != NULL) {
				const char *s = smb_fname->stream_name;
				const char *e = NULL;
				size_t n;

				SMB_ASSERT(s[0] != '\0');

				/*
				 * smb_fname->stream_name is in form
				 * of ':StrEam:$DATA', but we should only
				 * append ':StrEam' here.
				 */

				e = strchr(&s[1], ':');
				if (e == NULL) {
					n = strlen(s);
				} else {
					n = PTR_DIFF(e, s);
				}
				nfname = talloc_strndup_append(nfname, s, n);
				if (nfname == NULL) {
					return NT_STATUS_NO_MEMORY;
				}
			}

			status = srvstr_push(dstart, flags2,
					  pdata+4, nfname,
					  PTR_DIFF(dend, pdata+4),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NORMALIZED_NAME_INFORMATION\n"));
			data_size = 4 + len;
			SIVAL(pdata,0,len);
			*fixed_portion = 8;
			break;
		}

		case SMB_FILE_ALLOCATION_INFORMATION:
		case SMB_QUERY_FILE_ALLOCATION_INFO:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
			data_size = 8;
			SOFF_T(pdata,0,allocation_size);
			break;

		case SMB_FILE_END_OF_FILE_INFORMATION:
		case SMB_QUERY_FILE_END_OF_FILEINFO:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
			data_size = 8;
			SOFF_T(pdata,0,file_size);
			break;

		case SMB_QUERY_FILE_ALL_INFO:
		case SMB_FILE_ALL_INFORMATION:
		{
			unsigned int ea_size =
			    estimate_ea_size(smb_fname->fsp);
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
			put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
			put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
			SIVAL(pdata,32,mode);
			SIVAL(pdata,36,0); /* padding. */
			pdata += 40;
			SOFF_T(pdata,0,allocation_size);
			SOFF_T(pdata,8,file_size);
			SIVAL(pdata,16,nlink);
			SCVAL(pdata,20,delete_pending);
			SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
			SSVAL(pdata,22,0);
			pdata += 24;
			SIVAL(pdata,0,ea_size);
			pdata += 4; /* EA info */
			status = srvstr_push(dstart, flags2,
					  pdata+4, dos_fname,
					  PTR_DIFF(dend, pdata+4),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SIVAL(pdata,0,len);
			pdata += 4 + len;
			data_size = PTR_DIFF(pdata,(*ppdata));
			*fixed_portion = 10;
			break;
		}

		case SMB2_FILE_ALL_INFORMATION:
		{
			unsigned int ea_size =
			    estimate_ea_size(smb_fname->fsp);
			DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
			put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */
			put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */
			SIVAL(pdata,	0x20, mode);
			SIVAL(pdata,	0x24, 0); /* padding. */
			SBVAL(pdata,	0x28, allocation_size);
			SBVAL(pdata,	0x30, file_size);
			SIVAL(pdata,	0x38, nlink);
			SCVAL(pdata,	0x3C, delete_pending);
			SCVAL(pdata,	0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
			SSVAL(pdata,	0x3E, 0); /* padding */
			SBVAL(pdata,	0x40, file_id);
			SIVAL(pdata,	0x48, ea_size);
			SIVAL(pdata,	0x4C, access_mask);
			SBVAL(pdata,	0x50, pos);
			SIVAL(pdata,	0x58, mode); /*TODO: mode != mode fix this!!! */
			SIVAL(pdata,	0x5C, 0); /* No alignment needed. */

			pdata += 0x60;

			status = srvstr_push(dstart, flags2,
					  pdata+4, dos_fname,
					  PTR_DIFF(dend, pdata+4),
					  STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SIVAL(pdata,0,len);
			pdata += 4 + len;
			data_size = PTR_DIFF(pdata,(*ppdata));
			*fixed_portion = 104;
			break;
		}
		case SMB_FILE_INTERNAL_INFORMATION:

			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
			SBVAL(pdata, 0, file_id);
			data_size = 8;
			*fixed_portion = 8;
			break;

		case SMB_FILE_ACCESS_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
			SIVAL(pdata, 0, access_mask);
			data_size = 4;
			*fixed_portion = 4;
			break;

		case SMB_FILE_NAME_INFORMATION:
			/* Pathname with leading '\'. */
			{
				size_t byte_len;
				byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
				DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
				SIVAL(pdata,0,byte_len);
				data_size = 4 + byte_len;
				break;
			}

		case SMB_FILE_DISPOSITION_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
			data_size = 1;
			SCVAL(pdata,0,delete_pending);
			*fixed_portion = 1;
			break;

		case SMB_FILE_POSITION_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
			data_size = 8;
			SOFF_T(pdata,0,pos);
			*fixed_portion = 8;
			break;

		case SMB_FILE_MODE_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
			SIVAL(pdata,0,mode);
			data_size = 4;
			*fixed_portion = 4;
			break;

		case SMB_FILE_ALIGNMENT_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
			SIVAL(pdata,0,0); /* No alignment needed. */
			data_size = 4;
			*fixed_portion = 4;
			break;

		/*
		 * NT4 server just returns "invalid query" to this - if we try
		 * to answer it then NTws gets a BSOD! (tridge).  W2K seems to
		 * want this. JRA.
		 */
		/* The first statement above is false - verified using Thursby
		 * client against NT4 -- gcolley.
		 */
		case SMB_QUERY_FILE_STREAM_INFO:
		case SMB_FILE_STREAM_INFORMATION: {
			unsigned int num_streams = 0;
			struct stream_struct *streams = NULL;

			DEBUG(10,("smbd_do_qfilepathinfo: "
				  "SMB_FILE_STREAM_INFORMATION\n"));

			if (is_ntfs_stream_smb_fname(smb_fname)) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			status = vfs_fstreaminfo(fsp,
						mem_ctx,
						&num_streams,
						&streams);

			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(10, ("could not get stream info: %s\n",
					   nt_errstr(status)));
				return status;
			}

			status = marshall_stream_info(num_streams, streams,
						      pdata, max_data_bytes,
						      &data_size);

			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(10, ("marshall_stream_info failed: %s\n",
					   nt_errstr(status)));
				TALLOC_FREE(streams);
				return status;
			}

			TALLOC_FREE(streams);

			*fixed_portion = 32;

			break;
		}
		case SMB_QUERY_COMPRESSION_INFO:
		case SMB_FILE_COMPRESSION_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
			SOFF_T(pdata,0,file_size);
			SIVAL(pdata,8,0); /* ??? */
			SIVAL(pdata,12,0); /* ??? */
			data_size = 16;
			*fixed_portion = 16;
			break;

		case SMB_FILE_NETWORK_OPEN_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
			put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
			put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
			put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
			SOFF_T(pdata,32,allocation_size);
			SOFF_T(pdata,40,file_size);
			SIVAL(pdata,48,mode);
			SIVAL(pdata,52,0); /* ??? */
			data_size = 56;
			*fixed_portion = 56;
			break;

		case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
			SIVAL(pdata,0,mode);
			SIVAL(pdata,4,0);
			data_size = 8;
			*fixed_portion = 8;
			break;

		/*
		 * CIFS UNIX Extensions.
		 */

		case SMB_QUERY_FILE_UNIX_BASIC:

			pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
			data_size = PTR_DIFF(pdata,(*ppdata));

			DEBUG(4,("smbd_do_qfilepathinfo: "
				 "SMB_QUERY_FILE_UNIX_BASIC\n"));
			dump_data(4, (uint8_t *)(*ppdata), data_size);

			break;

		case SMB_QUERY_FILE_UNIX_INFO2:

			pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
			data_size = PTR_DIFF(pdata,(*ppdata));

			{
				int i;
				DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));

				for (i=0; i<100; i++)
					DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
				DEBUG(4,("\n"));
			}

			break;

		case SMB_QUERY_FILE_UNIX_LINK:
			{
				status = smb_unix_read_symlink(conn,
							req,
							smb_fname,
							pdata,
							data_size,
							&data_size);
				if (!NT_STATUS_IS_OK(status)) {
					return status;
				}
				break;
			}

#if defined(HAVE_POSIX_ACLS)
		case SMB_QUERY_POSIX_ACL:
			{
				status = smb_query_posix_acl(conn,
							req,
							fsp,
							smb_fname,
							pdata,
							data_size,
							&data_size);
				if (!NT_STATUS_IS_OK(status)) {
					return status;
				}
				break;
			}
#endif


		case SMB_QUERY_POSIX_LOCK:
		{
			uint64_t count;
			uint64_t offset;
			uint64_t smblctx;
			enum brl_type lock_type;

			/* We need an open file with a real fd for this. */
			if (fsp == NULL ||
			    fsp->fsp_flags.is_pathref ||
			    fsp_get_io_fd(fsp) == -1)
			{
				return NT_STATUS_INVALID_LEVEL;
			}

			if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
				case POSIX_LOCK_TYPE_READ:
					lock_type = READ_LOCK;
					break;
				case POSIX_LOCK_TYPE_WRITE:
					lock_type = WRITE_LOCK;
					break;
				case POSIX_LOCK_TYPE_UNLOCK:
				default:
					/* There's no point in asking for an unlock... */
					return NT_STATUS_INVALID_PARAMETER;
			}

			smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
			offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
			count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);

			status = query_lock(fsp,
					&smblctx,
					&count,
					&offset,
					&lock_type,
					POSIX_LOCK);

			if (ERROR_WAS_LOCK_DENIED(status)) {
				/* Here we need to report who has it locked... */
				data_size = POSIX_LOCK_DATA_SIZE;

				SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
				SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
				SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
				SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
				SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);

			} else if (NT_STATUS_IS_OK(status)) {
				/* For success we just return a copy of what we sent
				   with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
				data_size = POSIX_LOCK_DATA_SIZE;
				memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
				SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
			} else {
				return status;
			}
			break;
		}

		default:
			return NT_STATUS_INVALID_LEVEL;
	}

	*pdata_size = data_size;
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
				const char *pdata,
				int total_data,
				files_struct *fsp)
{
	struct ea_list *ea_list = NULL;
	NTSTATUS status;

	if (fsp == NULL) {
		return NT_STATUS_INVALID_HANDLE;
	}

	if (!lp_ea_support(SNUM(conn))) {
		DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
			"EA's not supported.\n",
			(unsigned int)total_data));
		return NT_STATUS_EAS_NOT_SUPPORTED;
	}

	if (total_data < 10) {
		DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
			"too small.\n",
			(unsigned int)total_data));
		return NT_STATUS_INVALID_PARAMETER;
	}

	ea_list = read_nttrans_ea_list(talloc_tos(),
				pdata,
				total_data);

	if (!ea_list) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	status = set_ea(conn, fsp, ea_list);

	DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
		smb_fname_str_dbg(fsp->fsp_name),
		nt_errstr(status) ));

	return status;
}

Project: samba
File: trans2.c

static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
				    connection_struct *conn,
				    uint16_t flags2,
				    uint32_t info_level,
				    struct ea_list *name_list,
				    bool check_mangled_names,
				    bool requires_resume_key,
				    uint32_t mode,
				    const char *fname,
				    const struct smb_filename *smb_fname,
				    int space_remaining,
				    uint8_t align,
				    bool do_pad,
				    char *base_data,
				    char **ppdata,
				    char *end_data,
				    uint64_t *last_entry_off)
{
	char *p, *q, *pdata = *ppdata;
	uint32_t reskey=0;
	uint64_t file_size = 0;
	uint64_t allocation_size = 0;
	uint64_t file_id = 0;
	size_t len = 0;
	struct timespec mdate_ts = {0};
	struct timespec adate_ts = {0};
	struct timespec cdate_ts = {0};
	struct timespec create_date_ts = {0};
	time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
	char *nameptr;
	char *last_entry_ptr;
	bool was_8_3;
	int off;
	int pad = 0;
	NTSTATUS status;
	struct readdir_attr_data *readdir_attr_data = NULL;

	if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
		file_size = get_file_size_stat(&smb_fname->st);
	}
	allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);

	/*
	 * Skip SMB_VFS_FREADDIR_ATTR if the directory entry is a symlink or
	 * a DFS symlink.
	 */
	if (smb_fname->fsp != NULL &&
	    !(mode & FILE_ATTRIBUTE_REPARSE_POINT)) {
		status = SMB_VFS_FREADDIR_ATTR(smb_fname->fsp,
					       ctx,
					       &readdir_attr_data);
		if (!NT_STATUS_IS_OK(status)) {
			if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED,
					     status)) {
				return status;
			}
		}
	}

	file_id = SMB_VFS_FS_FILE_ID(conn, &smb_fname->st);

	mdate_ts = smb_fname->st.st_ex_mtime;
	adate_ts = smb_fname->st.st_ex_atime;
	create_date_ts = get_create_timespec(conn, NULL, smb_fname);
	cdate_ts = get_change_timespec(conn, NULL, smb_fname);

	if (lp_dos_filetime_resolution(SNUM(conn))) {
		dos_filetime_timespec(&create_date_ts);
		dos_filetime_timespec(&mdate_ts);
		dos_filetime_timespec(&adate_ts);
		dos_filetime_timespec(&cdate_ts);
	}

	create_date = convert_timespec_to_time_t(create_date_ts);
	mdate = convert_timespec_to_time_t(mdate_ts);
	adate = convert_timespec_to_time_t(adate_ts);

	/* align the record */
	SMB_ASSERT(align >= 1);

	off = (int)PTR_DIFF(pdata, base_data);
	pad = (off + (align-1)) & ~(align-1);
	pad -= off;

	if (pad && pad > space_remaining) {
		DEBUG(9,("smbd_marshall_dir_entry: out of space "
			"for padding (wanted %u, had %d)\n",
			(unsigned int)pad,
			space_remaining ));
		return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
	}

	off += pad;
	/* initialize padding to 0 */
	if (pad) {
		memset(pdata, 0, pad);
	}
	space_remaining -= pad;

	DEBUG(10,("smbd_marshall_dir_entry: space_remaining = %d\n",
		space_remaining ));

	pdata += pad;
	p = pdata;
	last_entry_ptr = p;

	pad = 0;
	off = 0;

	switch (info_level) {
	case SMB_FIND_INFO_STANDARD:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
		if(requires_resume_key) {
			SIVAL(p,0,reskey);
			p += 4;
		}
		srv_put_dos_date2(p,0,create_date);
		srv_put_dos_date2(p,4,adate);
		srv_put_dos_date2(p,8,mdate);
		SIVAL(p,12,(uint32_t)file_size);
		SIVAL(p,16,(uint32_t)allocation_size);
		SSVAL(p,20,mode);
		p += 23;
		nameptr = p;
		if (flags2 & FLAGS2_UNICODE_STRINGS) {
			p += ucs2_align(base_data, p, 0);
		}
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		if (flags2 & FLAGS2_UNICODE_STRINGS) {
			if (len > 2) {
				SCVAL(nameptr, -1, len - 2);
			} else {
				SCVAL(nameptr, -1, 0);
			}
		} else {
			if (len > 1) {
				SCVAL(nameptr, -1, len - 1);
			} else {
				SCVAL(nameptr, -1, 0);
			}
		}
		p += len;
		break;

	case SMB_FIND_EA_SIZE:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
		if (requires_resume_key) {
			SIVAL(p,0,reskey);
			p += 4;
		}
		srv_put_dos_date2(p,0,create_date);
		srv_put_dos_date2(p,4,adate);
		srv_put_dos_date2(p,8,mdate);
		SIVAL(p,12,(uint32_t)file_size);
		SIVAL(p,16,(uint32_t)allocation_size);
		SSVAL(p,20,mode);
		{
			unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
			SIVAL(p,22,ea_size); /* Extended attributes */
		}
		p += 27;
		nameptr = p - 1;
		status = srvstr_push(base_data, flags2,
				  p, fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE | STR_NOALIGN, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		if (flags2 & FLAGS2_UNICODE_STRINGS) {
			if (len > 2) {
				len -= 2;
			} else {
				len = 0;
			}
		} else {
			if (len > 1) {
				len -= 1;
			} else {
				len = 0;
			}
		}
		SCVAL(nameptr,0,len);
		p += len;
		SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
		break;

	case SMB_FIND_EA_LIST:
	{
		struct ea_list *file_list = NULL;
		size_t ea_len = 0;

		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
		if (!name_list) {
			return NT_STATUS_INVALID_PARAMETER;
		}
		if (requires_resume_key) {
			SIVAL(p,0,reskey);
			p += 4;
		}
		srv_put_dos_date2(p,0,create_date);
		srv_put_dos_date2(p,4,adate);
		srv_put_dos_date2(p,8,mdate);
		SIVAL(p,12,(uint32_t)file_size);
		SIVAL(p,16,(uint32_t)allocation_size);
		SSVAL(p,20,mode);
		p += 22; /* p now points to the EA area. */

		status = get_ea_list_from_fsp(ctx,
					       smb_fname->fsp,
					       &ea_len, &file_list);
		if (!NT_STATUS_IS_OK(status)) {
			file_list = NULL;
		}
		name_list = ea_list_union(name_list, file_list, &ea_len);

		/* We need to determine if this entry will fit in the space available. */
		/* Max string size is 255 bytes. */
		if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
			DEBUG(9,("smbd_marshall_dir_entry: out of space "
				"(wanted %u, had %d)\n",
				(unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
				space_remaining ));
			return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
		}

		/* Push the ea_data followed by the name. */
		p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
		nameptr = p;
		status = srvstr_push(base_data, flags2,
				  p + 1, fname, PTR_DIFF(end_data, p+1),
				  STR_TERMINATE | STR_NOALIGN, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		if (flags2 & FLAGS2_UNICODE_STRINGS) {
			if (len > 2) {
				len -= 2;
			} else {
				len = 0;
			}
		} else {
			if (len > 1) {
				len -= 1;
			} else {
				len = 0;
			}
		}
		SCVAL(nameptr,0,len);
		p += len + 1;
		SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
		break;
	}

	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
		was_8_3 = mangle_is_8_3(fname, True, conn->params);
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
		SOFF_T(p,0,file_size); p += 8;
		SOFF_T(p,0,allocation_size); p += 8;
		SIVAL(p,0,mode); p += 4;
		q = p; p += 4; /* q is placeholder for name length. */
		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
		} else {
			unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
			SIVAL(p,0,ea_size); /* Extended attributes */
		}
		p += 4;
		/* Clear the short name buffer. This is
		 * IMPORTANT as not doing so will trigger
		 * a Win2k client bug. JRA.
		 */
		if (!was_8_3 && check_mangled_names) {
			char mangled_name[13]; /* mangled 8.3 name. */
			if (!name_to_8_3(fname,mangled_name,True,
					   conn->params)) {
				/* Error - mangle failed ! */
				memset(mangled_name,'\0',12);
			}
			mangled_name[12] = 0;
			status = srvstr_push(base_data, flags2,
					  p+2, mangled_name, 24,
					  STR_UPPER|STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			if (len < 24) {
				memset(p + 2 + len,'\0',24 - len);
			}
			SSVAL(p, 0, len);
		} else {
			memset(p,'\0',26);
		}
		p += 2 + 24;
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(q,0,len);
		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	case SMB_FIND_FILE_DIRECTORY_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
		SOFF_T(p,0,file_size); p += 8;
		SOFF_T(p,0,allocation_size); p += 8;
		SIVAL(p,0,mode); p += 4;
		status = srvstr_push(base_data, flags2,
				  p + 4, fname, PTR_DIFF(end_data, p+4),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(p,0,len);
		p += 4 + len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
		SOFF_T(p,0,file_size); p += 8;
		SOFF_T(p,0,allocation_size); p += 8;
		SIVAL(p,0,mode); p += 4;
		q = p; p += 4; /* q is placeholder for name length. */
		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
		} else {
			unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
			SIVAL(p,0,ea_size); /* Extended attributes */
		}
		p +=4;
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(q, 0, len);
		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	case SMB_FIND_FILE_NAMES_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		p += 4;
		/* this must *not* be null terminated or w2k gets in a loop trying to set an
		   acl on a dir (tridge) */
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(p, -4, len);
		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	case SMB_FIND_ID_FULL_DIRECTORY_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
		SOFF_T(p,0,file_size); p += 8;
		SOFF_T(p,0,allocation_size); p += 8;
		SIVAL(p,0,mode); p += 4;
		q = p; p += 4; /* q is placeholder for name length. */
		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
		} else {
			unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
			SIVAL(p,0,ea_size); /* Extended attributes */
		}
		p += 4;
		SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
		SBVAL(p,0,file_id); p += 8;
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(q, 0, len);
		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
		DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
		was_8_3 = mangle_is_8_3(fname, True, conn->params);
		p += 4;
		SIVAL(p,0,reskey); p += 4;
		put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
		put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
		SOFF_T(p,0,file_size); p += 8;
		SOFF_T(p,0,allocation_size); p += 8;
		SIVAL(p,0,mode); p += 4;
		q = p; p += 4; /* q is placeholder for name length */
		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
		} else if (readdir_attr_data &&
			   readdir_attr_data->type == RDATTR_AAPL) {
			/*
			 * OS X specific SMB2 extension negotiated via
			 * AAPL create context: return max_access in
			 * ea_size field.
			 */
			SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
		} else {
			unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
			SIVAL(p,0,ea_size); /* Extended attributes */
		}
		p += 4;

		if (readdir_attr_data &&
		    readdir_attr_data->type == RDATTR_AAPL) {
			/*
			 * OS X specific SMB2 extension negotiated via
			 * AAPL create context: return resource fork
			 * length and compressed FinderInfo in
			 * shortname field.
			 *
			 * According to documentation short_name_len
			 * should be 0, but on the wire behaviour
			 * shows its set to 24 by clients.
			 */
			SSVAL(p, 0, 24);

			/* Resourefork length */
			SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);

			/* Compressed FinderInfo */
			memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
		} else if (!was_8_3 && check_mangled_names) {
			char mangled_name[13]; /* mangled 8.3 name. */
			if (!name_to_8_3(fname,mangled_name,True,
					conn->params)) {
				/* Error - mangle failed ! */
				memset(mangled_name,'\0',12);
			}
			mangled_name[12] = 0;
			status = srvstr_push(base_data, flags2,
					  p+2, mangled_name, 24,
					  STR_UPPER|STR_UNICODE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SSVAL(p, 0, len);
			if (len < 24) {
				memset(p + 2 + len,'\0',24 - len);
			}
			SSVAL(p, 0, len);
		} else {
			/* Clear the short name buffer. This is
			 * IMPORTANT as not doing so will trigger
			 * a Win2k client bug. JRA.
			 */
			memset(p,'\0',26);
		}
		p += 26;

		/* Reserved ? */
		if (readdir_attr_data &&
		    readdir_attr_data->type == RDATTR_AAPL) {
			/*
			 * OS X specific SMB2 extension negotiated via
			 * AAPL create context: return UNIX mode in
			 * reserved field.
			 */
			uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
			SSVAL(p, 0, aapl_mode);
		} else {
			SSVAL(p, 0, 0);
		}
		p += 2;

		SBVAL(p,0,file_id); p += 8;
		status = srvstr_push(base_data, flags2, p,
				  fname, PTR_DIFF(end_data, p),
				  STR_TERMINATE_ASCII, &len);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		SIVAL(q,0,len);
		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		break;

	/* CIFS UNIX Extension. */

	case SMB_FIND_FILE_UNIX:
	case SMB_FIND_FILE_UNIX_INFO2:
		p+= 4;
		SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */

		/* Begin of SMB_QUERY_FILE_UNIX_BASIC */

		if (info_level == SMB_FIND_FILE_UNIX) {
			DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
			p = store_file_unix_basic(conn, p,
						NULL, &smb_fname->st);
			status = srvstr_push(base_data, flags2, p,
					  fname, PTR_DIFF(end_data, p),
					  STR_TERMINATE, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
		} else {
			DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
			p = store_file_unix_basic_info2(conn, p,
						NULL, &smb_fname->st);
			nameptr = p;
			p += 4;
			status = srvstr_push(base_data, flags2, p, fname,
					  PTR_DIFF(end_data, p), 0, &len);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			SIVAL(nameptr, 0, len);
		}

		p += len;

		len = PTR_DIFF(p, pdata);
		pad = (len + (align-1)) & ~(align-1);
		/*
		 * offset to the next entry, the caller
		 * will overwrite it for the last entry
		 * that's why we always include the padding
		 */
		SIVAL(pdata,0,pad);
		/*
		 * set padding to zero
		 */
		if (do_pad) {
			memset(p, 0, pad - len);
			p = pdata + pad;
		} else {
			p = pdata + len;
		}
		/* End of SMB_QUERY_FILE_UNIX_BASIC */

		break;

	default:
		return NT_STATUS_INVALID_LEVEL;
	}

	if (PTR_DIFF(p,pdata) > space_remaining) {
		DEBUG(9,("smbd_marshall_dir_entry: out of space "
			"(wanted %u, had %d)\n",
			(unsigned int)PTR_DIFF(p,pdata),
			space_remaining ));
		return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
	}

	/* Setup the last entry pointer, as an offset from base_data */
	*last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
	/* Advance the data pointer to the next slot */
	*ppdata = p;

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static unsigned int estimate_ea_size(files_struct *fsp)
{
	size_t total_ea_len = 0;
	TALLOC_CTX *mem_ctx;
	struct ea_list *ea_list = NULL;
	NTSTATUS status;

	/* symlink */
	if (fsp == NULL) {
		return 0;
	}

	if (!lp_ea_support(SNUM(fsp->conn))) {
		return 0;
	}

	mem_ctx = talloc_stackframe();

	/* If this is a stream fsp, then we need to instead find the
	 * estimated ea len from the main file, not the stream
	 * (streams cannot have EAs), but the estimate isn't just 0 in
	 * this case! */
	if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
		fsp = fsp->base_fsp;
	}
	(void)get_ea_list_from_fsp(mem_ctx,
				   fsp,
				   &total_ea_len,
				   &ea_list);

	if(fsp->conn->sconn->using_smb2) {
		unsigned int ret_data_size;
		/*
		 * We're going to be using fill_ea_chained_buffer() to
		 * marshall EA's - this size is significantly larger
		 * than the SMB1 buffer. Re-calculate the size without
		 * marshalling.
		 */
		status = fill_ea_chained_buffer(mem_ctx,
						NULL,
						0,
						&ret_data_size,
						fsp->conn,
						ea_list);
		if (!NT_STATUS_IS_OK(status)) {
			ret_data_size = 0;
		}
		total_ea_len = ret_data_size;
	}
	TALLOC_FREE(mem_ctx);
	return total_ea_len;
}

Project: samba
File: trans2.c

static NTSTATUS smb_file_rename_information(connection_struct *conn,
					    struct smb_request *req,
					    const char *pdata,
					    int total_data,
					    files_struct *fsp,
					    struct smb_filename *smb_fname_src)
{
	bool overwrite;
	uint32_t root_fid;
	uint32_t len;
	char *newname = NULL;
	struct smb_filename *smb_fname_dst = NULL;
	const char *dst_original_lcomp = NULL;
	NTSTATUS status = NT_STATUS_OK;
	char *p;
	TALLOC_CTX *ctx = talloc_tos();

	if (total_data < 13) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	overwrite = (CVAL(pdata,0) ? True : False);
	root_fid = IVAL(pdata,4);
	len = IVAL(pdata,8);

	if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (req->posix_pathnames) {
		srvstr_get_path_posix(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[12],
				len,
				0,
				&status);
	} else {
		srvstr_get_path(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[12],
				len,
				0,
				&status);
	}
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	DEBUG(10,("smb_file_rename_information: got name |%s|\n",
				newname));

	/* Check the new name has no '/' characters. */
	if (strchr_m(newname, '/')) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (fsp && fsp->base_fsp) {
		/* newname must be a stream name. */
		if (newname[0] != ':') {
			return NT_STATUS_NOT_SUPPORTED;
		}

		/* Create an smb_fname to call rename_internals_fsp() with. */
		smb_fname_dst = synthetic_smb_fname(talloc_tos(),
					fsp->base_fsp->fsp_name->base_name,
					newname,
					NULL,
					fsp->base_fsp->fsp_name->twrp,
					fsp->base_fsp->fsp_name->flags);
		if (smb_fname_dst == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto out;
		}

		/*
		 * Get the original last component, since
		 * rename_internals_fsp() requires it.
		 */
		dst_original_lcomp = get_original_lcomp(smb_fname_dst,
					conn,
					newname,
					0);
		if (dst_original_lcomp == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto out;
		}

	} else {
		/*
		 * Build up an smb_fname_dst based on the filename passed in.
		 * We basically just strip off the last component, and put on
		 * the newname instead.
		 */
		char *base_name = NULL;
		uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP|
				ucf_flags_from_smb_request(req);

		/* newname must *not* be a stream name. */
		if (newname[0] == ':') {
			return NT_STATUS_NOT_SUPPORTED;
		}

		/*
		 * Strip off the last component (filename) of the path passed
		 * in.
		 */
		base_name = talloc_strdup(ctx, smb_fname_src->base_name);
		if (!base_name) {
			return NT_STATUS_NO_MEMORY;
		}
		p = strrchr_m(base_name, '/');
		if (p) {
			p[1] = '\0';
		} else {
			base_name = talloc_strdup(ctx, "");
			if (!base_name) {
				return NT_STATUS_NO_MEMORY;
			}
		}
		/* Append the new name. */
		base_name = talloc_asprintf_append(base_name,
				"%s",
				newname);
		if (!base_name) {
			return NT_STATUS_NO_MEMORY;
		}

		status = filename_convert(ctx,
					  conn,
					  base_name,
					  ucf_flags,
					  0,
					  &smb_fname_dst);

		/* If an error we expect this to be
		 * NT_STATUS_OBJECT_PATH_NOT_FOUND */

		if (!NT_STATUS_IS_OK(status)) {
			if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
					    status)) {
				goto out;
			}
			/* Create an smb_fname to call rename_internals_fsp() */
			smb_fname_dst = synthetic_smb_fname(ctx,
						base_name,
						NULL,
						NULL,
						smb_fname_src->twrp,
						smb_fname_src->flags);
			if (smb_fname_dst == NULL) {
				status = NT_STATUS_NO_MEMORY;
				goto out;
			}
		}
		dst_original_lcomp = get_original_lcomp(smb_fname_dst,
					conn,
					newname,
					ucf_flags);
		if (dst_original_lcomp == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto out;
		}
	}

	if (fsp != NULL && fsp->fsp_flags.is_fsa) {
		DEBUG(10,("smb_file_rename_information: "
			  "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
			  fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
			  smb_fname_str_dbg(smb_fname_dst)));
		status = rename_internals_fsp(conn,
					fsp,
					smb_fname_dst,
					dst_original_lcomp,
					0,
					overwrite);
	} else {
		DEBUG(10,("smb_file_rename_information: "
			  "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
			  smb_fname_str_dbg(smb_fname_src),
			  smb_fname_str_dbg(smb_fname_dst)));
		status = rename_internals(ctx,
					conn,
					req,
					smb_fname_src,
					NULL,
					smb_fname_dst,
					dst_original_lcomp,
					0,
					overwrite,
					FILE_WRITE_ATTRIBUTES);
	}
 out:
	TALLOC_FREE(smb_fname_dst);
	return status;
}

Project: samba
File: trans2.c

static void smb_set_posix_lock_done(struct tevent_req *subreq)
{
	struct smb_request *req = NULL;
	NTSTATUS status;
	bool ok;

	ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
	SMB_ASSERT(ok);

	status = smbd_smb1_do_locks_recv(subreq);
	TALLOC_FREE(subreq);

	if (NT_STATUS_IS_OK(status)) {
		char params[2] = {0};
		/* Fake up max_data_bytes here - we know it fits. */
		send_trans2_replies(
			req->conn,
			req,
			NT_STATUS_OK,
			params,
			2,
			NULL,
			0,
			0xffff);
	} else {
		reply_nterror(req, status);
		ok = srv_send_smb(
			req->xconn,
			(char *)req->outbuf,
			true,
			req->seqnum+1,
			IS_CONN_ENCRYPTED(req->conn),
			NULL);
		if (!ok) {
			exit_server_cleanly("smb_set_posix_lock_done: "
					    "srv_send_smb failed.");
		}
	}

	TALLOC_FREE(req);
	return;
}

Project: samba
File: trans2.c

static void call_trans2setfilepathinfo(connection_struct *conn,
				       struct smb_request *req,
				       unsigned int tran_call,
				       char **pparams, int total_params,
				       char **ppdata, int total_data,
				       unsigned int max_data_bytes)
{
	char *params = *pparams;
	char *pdata = *ppdata;
	uint16_t info_level;
	struct smb_filename *smb_fname = NULL;
	files_struct *fsp = NULL;
	NTSTATUS status = NT_STATUS_OK;
	int data_return_size = 0;

	if (!params) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	if (tran_call == TRANSACT2_SETFILEINFO) {
		if (total_params < 4) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			return;
		}

		fsp = file_fsp(req, SVAL(params,0));
		/* Basic check for non-null fsp. */
	        if (!check_fsp_open(conn, req, fsp)) {
			return;
		}
		info_level = SVAL(params,2);

		smb_fname = fsp->fsp_name;

		if (fsp_get_pathref_fd(fsp) == -1) {
			/*
			 * This is actually a SETFILEINFO on a directory
			 * handle (returned from an NT SMB). NT5.0 seems
			 * to do this call. JRA.
			 */
			if (INFO_LEVEL_IS_UNIX(info_level)) {
				/* Always do lstat for UNIX calls. */
				if (SMB_VFS_LSTAT(conn, smb_fname)) {
					DEBUG(3,("call_trans2setfilepathinfo: "
						 "SMB_VFS_LSTAT of %s failed "
						 "(%s)\n",
						 smb_fname_str_dbg(smb_fname),
						 strerror(errno)));
					reply_nterror(req, map_nt_error_from_unix(errno));
					return;
				}
			} else {
				if (SMB_VFS_STAT(conn, smb_fname) != 0) {
					DEBUG(3,("call_trans2setfilepathinfo: "
						 "fileinfo of %s failed (%s)\n",
						 smb_fname_str_dbg(smb_fname),
						 strerror(errno)));
					reply_nterror(req, map_nt_error_from_unix(errno));
					return;
				}
			}
		} else if (fsp->print_file) {
			/*
			 * Doing a DELETE_ON_CLOSE should cancel a print job.
			 */
			if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
				uint32_t new_private_options =
					fh_get_private_options(fsp->fh);
				new_private_options |=
					NTCREATEX_FLAG_DELETE_ON_CLOSE;
				fh_set_private_options(fsp->fh,
						       new_private_options);

				DEBUG(3,("call_trans2setfilepathinfo: "
					 "Cancelling print job (%s)\n",
					 fsp_str_dbg(fsp)));

				SSVAL(params,0,0);
				send_trans2_replies(conn, req, NT_STATUS_OK, params, 2,
						    *ppdata, 0,
						    max_data_bytes);
				return;
			} else {
				reply_nterror(req,
					NT_STATUS_OBJECT_PATH_NOT_FOUND);
				return;
			}
		} else {
			/*
			 * Original code - this is an open file.
			 */
			if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
				DEBUG(3,("call_trans2setfilepathinfo: fstat "
					 "of %s failed (%s)\n", fsp_fnum_dbg(fsp),
					 strerror(errno)));
				reply_nterror(req, map_nt_error_from_unix(errno));
				return;
			}
		}
	} else {
		char *fname = NULL;
		uint32_t ucf_flags = ucf_flags_from_smb_request(req);

		/* set path info */
		if (total_params < 7) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			return;
		}

		info_level = SVAL(params,0);
		if (req->posix_pathnames) {
			srvstr_get_path_posix(req,
				params,
				req->flags2,
				&fname,
				&params[6],
				total_params - 6,
				STR_TERMINATE,
				&status);
		} else {
			srvstr_get_path(req,
				params,
				req->flags2,
				&fname,
				&params[6],
				total_params - 6,
				STR_TERMINATE,
				&status);
		}
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, status);
			return;
		}

		status = filename_convert(req, conn,
					 fname,
					 ucf_flags,
					 0,
					 &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,
						ERRSRV, ERRbadpath);
				return;
			}
			reply_nterror(req, status);
			return;
		}

		/*
		 * smb_fname->fsp may be NULL if smb_fname points at a symlink
		 * and we're in POSIX context, so be careful when using fsp
		 * below, it can still be NULL.
		 */
		fsp = smb_fname->fsp;

		if (INFO_LEVEL_IS_UNIX(info_level)) {
			/*
			 * For CIFS UNIX extensions the target name may not exist.
			 */

			/* Always do lstat for UNIX calls. */
			SMB_VFS_LSTAT(conn, smb_fname);

		} else if (!VALID_STAT(smb_fname->st) &&
			   SMB_VFS_STAT(conn, smb_fname)) {
			DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
				 "%s failed (%s)\n",
				 smb_fname_str_dbg(smb_fname),
				 strerror(errno)));
			reply_nterror(req, map_nt_error_from_unix(errno));
			return;
		}
	}

	DEBUG(3,("call_trans2setfilepathinfo(%d) %s (%s) info_level=%d "
		 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
		 fsp_fnum_dbg(fsp),
		 info_level,total_data));

	/* Realloc the parameter size */
	*pparams = (char *)SMB_REALLOC(*pparams,2);
	if (*pparams == NULL) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		return;
	}
	params = *pparams;

	SSVAL(params,0,0);

	status = smbd_do_setfilepathinfo(conn, req, req,
					 info_level,
					 fsp,
					 smb_fname,
					 ppdata, total_data,
					 &data_return_size);
	if (!NT_STATUS_IS_OK(status)) {
		if (open_was_deferred(req->xconn, req->mid)) {
			/* We have re-scheduled this call. */
			return;
		}
		if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
			bool ok = defer_smb1_sharing_violation(req);
			if (ok) {
				return;
			}
		}
		if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
			/* We have re-scheduled this call. */
			return;
		}
		if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
			reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
					ERRSRV, ERRbadpath);
			return;
		}
		if (info_level == SMB_POSIX_PATH_OPEN) {
			reply_openerror(req, status);
			return;
		}

		/*
		 * Invalid EA name needs to return 2 param bytes,
		 * not a zero-length error packet.
		 */
		if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
			send_trans2_replies(conn, req, status, params, 2, NULL, 0,
					max_data_bytes);
		} else {
			reply_nterror(req, status);
		}
		return;
	}

	send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, data_return_size,
			    max_data_bytes);

	return;
}

Project: samba
File: trans2.c

unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
{
	const struct loadparm_substitution *lp_sub =
		loadparm_s3_global_substitution();

	E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid);
	return objid;
}

Project: samba
File: trans2.c

uint64_t smb_roundup(connection_struct *conn, uint64_t val)
{
	uint64_t rval = lp_allocation_roundup_size(SNUM(conn));

	/* Only roundup for Windows clients. */
	enum remote_arch_types ra_type = get_remote_arch();
	if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
		val = SMB_ROUNDUP(val,rval);
	}
	return val;
}

Project: samba
File: trans2.c

static NTSTATUS smb_unix_mknod(connection_struct *conn,
					const char *pdata,
					int total_data,
					const struct smb_filename *smb_fname)
{
	uint32_t file_type = IVAL(pdata,56);
#if defined(HAVE_MAKEDEV)
	uint32_t dev_major = IVAL(pdata,60);
	uint32_t dev_minor = IVAL(pdata,68);
#endif
	SMB_DEV_T dev = (SMB_DEV_T)0;
	uint32_t raw_unixmode = IVAL(pdata,84);
	NTSTATUS status;
	mode_t unixmode;
	int ret;
	struct smb_filename *parent_fname = NULL;
	struct smb_filename *base_name = NULL;

	if (total_data < 100) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
				      PERM_NEW_FILE, &unixmode);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

#if defined(HAVE_MAKEDEV)
	dev = makedev(dev_major, dev_minor);
#endif

	switch (file_type) {
		/* We can't create other objects here. */
		case UNIX_TYPE_FILE:
		case UNIX_TYPE_DIR:
		case UNIX_TYPE_SYMLINK:
			return NT_STATUS_ACCESS_DENIED;
#if defined(S_IFIFO)
		case UNIX_TYPE_FIFO:
			unixmode |= S_IFIFO;
			break;
#endif
#if defined(S_IFSOCK)
		case UNIX_TYPE_SOCKET:
			unixmode |= S_IFSOCK;
			break;
#endif
#if defined(S_IFCHR)
		case UNIX_TYPE_CHARDEV:
			/* This is only allowed for root. */
			if (get_current_uid(conn) != sec_initial_uid()) {
				return NT_STATUS_ACCESS_DENIED;
			}
			unixmode |= S_IFCHR;
			break;
#endif
#if defined(S_IFBLK)
		case UNIX_TYPE_BLKDEV:
			if (get_current_uid(conn) != sec_initial_uid()) {
				return NT_STATUS_ACCESS_DENIED;
			}
			unixmode |= S_IFBLK;
			break;
#endif
		default:
			return NT_STATUS_INVALID_PARAMETER;
	}

	DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
		  "%.0f mode 0%o for file %s\n", (double)dev,
		  (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));

	status = parent_pathref(talloc_tos(),
				conn->cwd_fsp,
				smb_fname,
				&parent_fname,
				&base_name);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* Ok - do the mknod. */
	ret = SMB_VFS_MKNODAT(conn,
			parent_fname->fsp,
			base_name,
			unixmode,
			dev);

	if (ret != 0) {
		TALLOC_FREE(parent_fname);
		return map_nt_error_from_unix(errno);
	}

	/* If any of the other "set" calls fail we
 	 * don't want to end up with a half-constructed mknod.
 	 */

	if (lp_inherit_permissions(SNUM(conn))) {
		inherit_access_posix_acl(conn,
					 parent_fname,
					 smb_fname,
					 unixmode);
	}
	TALLOC_FREE(parent_fname);

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
					     struct smb_request *req,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname)
{
	uint64_t allocation_size = 0;
	NTSTATUS status = NT_STATUS_OK;
	files_struct *new_fsp = NULL;

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

	if (total_data < 8) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	allocation_size = (uint64_t)IVAL(pdata,0);
	allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
	DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
		  "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
		  (double)allocation_size));

	if (allocation_size) {
		allocation_size = smb_roundup(conn, allocation_size);
	}

	DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
		  "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
		  (double)allocation_size));

	if (fsp &&
	    !fsp->fsp_flags.is_pathref &&
	    fsp_get_io_fd(fsp) != -1)
	{
		/* Open file handle. */
		if (!(fsp->access_mask & FILE_WRITE_DATA)) {
			return NT_STATUS_ACCESS_DENIED;
		}

		/* Only change if needed. */
		if (allocation_size != get_file_size_stat(&smb_fname->st)) {
			if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
				return map_nt_error_from_unix(errno);
			}
		}
		/* But always update the time. */
		/*
		 * This is equivalent to a write. Ensure it's seen immediately
		 * if there are no pending writes.
		 */
		trigger_write_time_update_immediate(fsp);
		return NT_STATUS_OK;
	}

	/* Pathname or stat or directory file. */
	status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		FILE_WRITE_DATA,			/* access_mask */
		(FILE_SHARE_READ | FILE_SHARE_WRITE |	/* share_access */
		    FILE_SHARE_DELETE),
		FILE_OPEN,				/* create_disposition*/
		0,					/* create_options */
		FILE_ATTRIBUTE_NORMAL,			/* file_attributes */
		0,					/* oplock_request */
		NULL,					/* lease */
		0,					/* allocation_size */
		0,					/* private_flags */
		NULL,					/* sd */
		NULL,					/* ea_list */
		&new_fsp,				/* result */
		NULL,					/* pinfo */
		NULL, NULL);				/* create context */

	if (!NT_STATUS_IS_OK(status)) {
		/* NB. We check for open_was_deferred in the caller. */
		return status;
	}

	/* Only change if needed. */
	if (allocation_size != get_file_size_stat(&smb_fname->st)) {
		if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
			status = map_nt_error_from_unix(errno);
			close_file(req, new_fsp, NORMAL_CLOSE);
			return status;
		}
	}

	/* Changing the allocation size should set the last mod time. */
	/*
	 * This is equivalent to a write. Ensure it's seen immediately
	 * if there are no pending writes.
	 */
	trigger_write_time_update_immediate(new_fsp);
	close_file(req, new_fsp, NORMAL_CLOSE);
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_posix_open(connection_struct *conn,
			       struct smb_request *req,
				char **ppdata,
				int total_data,
				struct smb_filename *smb_fname,
				int *pdata_return_size)
{
	bool extended_oplock_granted = False;
	char *pdata = *ppdata;
	uint32_t flags = 0;
	uint32_t wire_open_mode = 0;
	uint32_t raw_unixmode = 0;
	uint32_t attributes = 0;
	uint32_t create_disp = 0;
	uint32_t access_mask = 0;
	uint32_t create_options = FILE_NON_DIRECTORY_FILE;
	NTSTATUS status = NT_STATUS_OK;
	mode_t unixmode = (mode_t)0;
	files_struct *fsp = NULL;
	int oplock_request = 0;
	int info = 0;
	uint16_t info_level_return = 0;
	struct smb2_create_blobs *posx = NULL;

	if (total_data < 18) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	flags = IVAL(pdata,0);
	oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
	if (oplock_request) {
		oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
	}

	wire_open_mode = IVAL(pdata,4);

	if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
		return smb_posix_mkdir(conn, req,
					ppdata,
					total_data,
					smb_fname,
					pdata_return_size);
	}

	switch (wire_open_mode & SMB_ACCMODE) {
		case SMB_O_RDONLY:
			access_mask = SMB_O_RDONLY_MAPPING;
			break;
		case SMB_O_WRONLY:
			access_mask = SMB_O_WRONLY_MAPPING;
			break;
		case SMB_O_RDWR:
			access_mask = (SMB_O_RDONLY_MAPPING|
					SMB_O_WRONLY_MAPPING);
			break;
		default:
			DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
				(unsigned int)wire_open_mode ));
			return NT_STATUS_INVALID_PARAMETER;
	}

	wire_open_mode &= ~SMB_ACCMODE;

	/* First take care of O_CREAT|O_EXCL interactions. */
	switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
		case (SMB_O_CREAT | SMB_O_EXCL):
			/* File exists fail. File not exist create. */
			create_disp = FILE_CREATE;
			break;
		case SMB_O_CREAT:
			/* File exists open. File not exist create. */
			create_disp = FILE_OPEN_IF;
			break;
		case SMB_O_EXCL:
			/* O_EXCL on its own without O_CREAT is undefined.
			   We deliberately ignore it as some versions of
			   Linux CIFSFS can send a bare O_EXCL on the
			   wire which other filesystems in the kernel
			   ignore. See bug 9519 for details. */

			/* Fallthrough. */

		case 0:
			/* File exists open. File not exist fail. */
			create_disp = FILE_OPEN;
			break;
		default:
			DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
				(unsigned int)wire_open_mode ));
			return NT_STATUS_INVALID_PARAMETER;
	}

	/* Next factor in the effects of O_TRUNC. */
	wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);

	if (wire_open_mode & SMB_O_TRUNC) {
		switch (create_disp) {
			case FILE_CREATE:
				/* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
				/* Leave create_disp alone as
				   (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
				*/
				/* File exists fail. File not exist create. */
				break;
			case FILE_OPEN_IF:
				/* SMB_O_CREAT | SMB_O_TRUNC */
				/* File exists overwrite. File not exist create. */
				create_disp = FILE_OVERWRITE_IF;
				break;
			case FILE_OPEN:
				/* SMB_O_TRUNC */
				/* File exists overwrite. File not exist fail. */
				create_disp = FILE_OVERWRITE;
				break;
			default:
				/* Cannot get here. */
				smb_panic("smb_posix_open: logic error");
				return NT_STATUS_INVALID_PARAMETER;
		}
	}

	raw_unixmode = IVAL(pdata,8);
	/* Next 4 bytes are not yet defined. */

	status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
				      (VALID_STAT(smb_fname->st) ?
					  PERM_EXISTING_FILE : PERM_NEW_FILE),
				      &unixmode);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
			    nt_errstr(status));
		return status;
	}

	if (wire_open_mode & SMB_O_SYNC) {
		create_options |= FILE_WRITE_THROUGH;
	}
	if (wire_open_mode & SMB_O_APPEND) {
		access_mask |= FILE_APPEND_DATA;
	}
	if (wire_open_mode & SMB_O_DIRECT) {
		attributes |= FILE_FLAG_NO_BUFFERING;
	}

	if ((wire_open_mode & SMB_O_DIRECTORY) ||
			VALID_STAT_OF_DIR(smb_fname->st)) {
		if (access_mask != SMB_O_RDONLY_MAPPING) {
			return NT_STATUS_FILE_IS_A_DIRECTORY;
		}
		create_options &= ~FILE_NON_DIRECTORY_FILE;
		create_options |= FILE_DIRECTORY_FILE;
	}

	DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
		smb_fname_str_dbg(smb_fname),
		(unsigned int)wire_open_mode,
		(unsigned int)unixmode ));

        status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		access_mask,				/* access_mask */
		(FILE_SHARE_READ | FILE_SHARE_WRITE |	/* share_access */
		    FILE_SHARE_DELETE),
		create_disp,				/* create_disposition*/
		create_options,				/* create_options */
		attributes,				/* file_attributes */
		oplock_request,				/* oplock_request */
		NULL,					/* lease */
		0,					/* allocation_size */
		0,					/* private_flags */
		NULL,					/* sd */
		NULL,					/* ea_list */
		&fsp,					/* result */
		&info,					/* pinfo */
		posx,					/* in_context_blobs */
		NULL);					/* out_context_blobs */

	TALLOC_FREE(posx);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
		extended_oplock_granted = True;
	}

	if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
		extended_oplock_granted = True;
	}

	info_level_return = SVAL(pdata,16);
 
	/* Allocate the correct return size. */

	if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
		*pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
	} else if (info_level_return ==  SMB_QUERY_FILE_UNIX_INFO2) {
		*pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
	} else {
		*pdata_return_size = 12;
	}

	/* Realloc the data size */
	*ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
	if (*ppdata == NULL) {
		close_file(req, fsp, ERROR_CLOSE);
		*pdata_return_size = 0;
		return NT_STATUS_NO_MEMORY;
	}
	pdata = *ppdata;

	if (extended_oplock_granted) {
		if (flags & REQUEST_BATCH_OPLOCK) {
			SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
		} else {
			SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
		}
	} else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
		SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
	} else {
		SSVAL(pdata,0,NO_OPLOCK_RETURN);
	}

	SSVAL(pdata,2,fsp->fnum);
	SIVAL(pdata,4,info); /* Was file created etc. */

	switch (info_level_return) {
		case SMB_QUERY_FILE_UNIX_BASIC:
			SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
			SSVAL(pdata,10,0); /* padding. */
			store_file_unix_basic(conn, pdata + 12, fsp,
					      &smb_fname->st);
			break;
		case SMB_QUERY_FILE_UNIX_INFO2:
			SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
			SSVAL(pdata,10,0); /* padding. */
			store_file_unix_basic_info2(conn, pdata + 12, fsp,
						    &smb_fname->st);
			break;
		default:
			SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
			SSVAL(pdata,10,0); /* padding. */
			break;
	}
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb2_file_rename_information(connection_struct *conn,
					    struct smb_request *req,
					    const char *pdata,
					    int total_data,
					    files_struct *fsp,
					    struct smb_filename *smb_fname_src)
{
	bool overwrite;
	uint32_t len;
	char *newname = NULL;
	struct smb_filename *smb_fname_dst = NULL;
	const char *dst_original_lcomp = NULL;
	uint32_t ucf_flags = ucf_flags_from_smb_request(req);
	NTSTATUS status = NT_STATUS_OK;
	TALLOC_CTX *ctx = talloc_tos();

	if (!fsp) {
		return NT_STATUS_INVALID_HANDLE;
	}

	if (total_data < 20) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	overwrite = (CVAL(pdata,0) ? True : False);
	len = IVAL(pdata,16);

	if (len > (total_data - 20) || (len == 0)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (req->posix_pathnames) {
		srvstr_get_path_posix(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[20],
				len,
				STR_TERMINATE,
				&status);
	} else {
		srvstr_get_path(ctx,
				pdata,
				req->flags2,
				&newname,
				&pdata[20],
				len,
				STR_TERMINATE,
				&status);
	}
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	DEBUG(10,("smb2_file_rename_information: got name |%s|\n",
				newname));

	status = filename_convert(ctx,
				conn,
				newname,
				ucf_flags,
				0,
				&smb_fname_dst);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (fsp->base_fsp) {
		/* newname must be a stream name. */
		if (newname[0] != ':') {
			return NT_STATUS_NOT_SUPPORTED;
		}

		/* Create an smb_fname to call rename_internals_fsp() with. */
		smb_fname_dst = synthetic_smb_fname(talloc_tos(),
					fsp->base_fsp->fsp_name->base_name,
					newname,
					NULL,
					fsp->base_fsp->fsp_name->twrp,
					fsp->base_fsp->fsp_name->flags);
		if (smb_fname_dst == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto out;
		}
	}

	/*
	 * Set the original last component, since
	 * rename_internals_fsp() requires it.
	 */
	dst_original_lcomp = get_original_lcomp(smb_fname_dst,
					conn,
					newname,
					ucf_flags);
	if (dst_original_lcomp == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}

	DEBUG(10,("smb2_file_rename_information: "
		  "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
		  fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
		  smb_fname_str_dbg(smb_fname_dst)));
	status = rename_internals_fsp(conn,
				fsp,
				smb_fname_dst,
				dst_original_lcomp,
				(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
				overwrite);

 out:
	TALLOC_FREE(smb_fname_dst);
	return status;
}

Project: samba
File: trans2.c

NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
		connection_struct *conn,
		struct smb_request *req,
		bool overwrite_if_exists,
		const struct smb_filename *smb_fname_old,
		struct smb_filename *smb_fname_new)
{
	NTSTATUS status = NT_STATUS_OK;
	int ret;
	bool ok;
	struct smb_filename *parent_fname_old = NULL;
	struct smb_filename *base_name_old = NULL;
	struct smb_filename *parent_fname_new = NULL;
	struct smb_filename *base_name_new = NULL;

	/* source must already exist. */
	if (!VALID_STAT(smb_fname_old->st)) {
		status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
		goto out;
	}

	/* No links from a directory. */
	if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
		status = NT_STATUS_FILE_IS_A_DIRECTORY;
		goto out;
	}

	/* Setting a hardlink to/from a stream isn't currently supported. */
	ok = is_ntfs_stream_smb_fname(smb_fname_old);
	if (ok) {
		DBG_DEBUG("Old name has streams\n");
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}
	ok = is_ntfs_stream_smb_fname(smb_fname_new);
	if (ok) {
		DBG_DEBUG("New name has streams\n");
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	status = parent_pathref(talloc_tos(),
				conn->cwd_fsp,
				smb_fname_old,
				&parent_fname_old,
				&base_name_old);
	if (!NT_STATUS_IS_OK(status)) {
		goto out;
	}

	status = parent_pathref(talloc_tos(),
				conn->cwd_fsp,
				smb_fname_new,
				&parent_fname_new,
				&base_name_new);
	if (!NT_STATUS_IS_OK(status)) {
		goto out;
	}

	if (VALID_STAT(smb_fname_new->st)) {
		if (overwrite_if_exists) {
			if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
				status = NT_STATUS_FILE_IS_A_DIRECTORY;
				goto out;
			}
			status = unlink_internals(conn,
						req,
						FILE_ATTRIBUTE_NORMAL,
						smb_fname_new,
						false);
			if (!NT_STATUS_IS_OK(status)) {
				goto out;
			}
		} else {
			/* Disallow if newname already exists. */
			status = NT_STATUS_OBJECT_NAME_COLLISION;
			goto out;
		}
	}

	DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
		  smb_fname_old->base_name, smb_fname_new->base_name));

	ret = SMB_VFS_LINKAT(conn,
			parent_fname_old->fsp,
			base_name_old,
			parent_fname_new->fsp,
			base_name_new,
			0);

	if (ret != 0) {
		status = map_nt_error_from_unix(errno);
		DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
			 nt_errstr(status), smb_fname_old->base_name,
			 smb_fname_new->base_name));
	}

  out:

	TALLOC_FREE(parent_fname_old);
	TALLOC_FREE(parent_fname_new);
	return status;
}

Project: samba
File: trans2.c

static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
					void *private_data,
					struct files_struct *dirfsp,
					struct smb_filename *atname,
					struct smb_filename *smb_fname,
					bool get_dosmode,
					uint32_t *_mode)
{
	struct smbd_dirptr_lanman2_state *state =
		(struct smbd_dirptr_lanman2_state *)private_data;
	bool ms_dfs_link = false;

	if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
		if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
			DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
				 "Couldn't lstat [%s] (%s)\n",
				 smb_fname_str_dbg(smb_fname),
				 strerror(errno)));
			return false;
		}
		return true;
	} else if (!VALID_STAT(smb_fname->st) &&
		   SMB_VFS_STAT(state->conn, smb_fname) != 0) {
		/* Needed to show the msdfs symlinks as
		 * directories */

		ms_dfs_link = check_msdfs_link(dirfsp,
					       atname,
					       smb_fname);
		if (!ms_dfs_link) {
			DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
				 "Couldn't stat [%s] (%s)\n",
				 smb_fname_str_dbg(smb_fname),
				 strerror(errno)));
			return false;
		}

		*_mode = dos_mode_msdfs(state->conn, smb_fname);
		return true;
	}

	if (!get_dosmode) {
		return true;
	}

	*_mode = fdos_mode(smb_fname->fsp);
	smb_fname->st = smb_fname->fsp->fsp_name->st;

	return true;
}

Project: samba
File: trans2.c

static NTSTATUS smb_unix_read_symlink(connection_struct *conn,
				struct smb_request *req,
				struct smb_filename *smb_fname,
				char *pdata,
				unsigned int data_size_in,
				unsigned int *pdata_size_out)
{
	NTSTATUS status;
	size_t len = 0;
	int link_len = 0;
	struct smb_filename *parent_fname = NULL;
	struct smb_filename *base_name = NULL;

	char *buffer = talloc_array(talloc_tos(), char, PATH_MAX+1);

	if (!buffer) {
		return NT_STATUS_NO_MEMORY;
	}

	DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
		smb_fname_str_dbg(smb_fname));

	if(!S_ISLNK(smb_fname->st.st_ex_mode)) {
		TALLOC_FREE(buffer);
		return NT_STATUS_DOS(ERRSRV, ERRbadlink);
	}

	status = parent_pathref(talloc_tos(),
				conn->cwd_fsp,
				smb_fname,
				&parent_fname,
				&base_name);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(buffer);
		return status;
	}

	link_len = SMB_VFS_READLINKAT(conn,
				parent_fname->fsp,
				base_name,
				buffer,
				PATH_MAX);

	TALLOC_FREE(parent_fname);

	if (link_len == -1) {
		TALLOC_FREE(buffer);
		return map_nt_error_from_unix(errno);
	}

	buffer[link_len] = 0;
	status = srvstr_push(pdata,
			req->flags2,
			pdata,
			buffer,
			data_size_in,
			STR_TERMINATE,
			&len);
	TALLOC_FREE(buffer);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}
	*pdata_size_out = len;

	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx,
				connection_struct *conn,
				struct dptr_struct *dirptr,
				uint16_t flags2,
				const char *path_mask,
				uint32_t dirtype,
				int info_level,
				bool requires_resume_key,
				bool dont_descend,
				bool ask_sharemode,
				char **ppdata,
				char *base_data,
				char *end_data,
				int space_remaining,
				bool *got_exact_match,
				int *last_entry_off,
				struct ea_list *name_list)
{
	uint8_t align = 4;
	const bool do_pad = true;

	if (info_level >= 1 && info_level <= 3) {
		/* No alignment on earlier info levels. */
		align = 1;
	}

	return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
					 path_mask, dirtype, info_level,
					 requires_resume_key, dont_descend, ask_sharemode,
					 true, align, do_pad,
					 ppdata, base_data, end_data,
					 space_remaining,
					 NULL,
					 got_exact_match,
					 last_entry_off, name_list, NULL);
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
				       struct smb_request *req,
				       const char *pdata,
				       int total_data,
				       struct smb_filename *new_smb_fname)
{
	char *link_target = NULL;
	struct smb_filename target_fname;
	TALLOC_CTX *ctx = talloc_tos();
	NTSTATUS status;
	int ret;
	struct smb_filename *parent_fname = NULL;
	struct smb_filename *base_name = NULL;

	/* Set a symbolic link. */
	/* Don't allow this if follow links is false. */

	if (total_data == 0) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!lp_follow_symlinks(SNUM(conn))) {
		return NT_STATUS_ACCESS_DENIED;
	}

	srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
		    total_data, STR_TERMINATE);

	if (!link_target) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	target_fname = (struct smb_filename) {
		.base_name = link_target,
	};

	/* Removes @GMT tokens if any */
	status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
			new_smb_fname->base_name, link_target ));

	status = parent_pathref(talloc_tos(),
				conn->cwd_fsp,
				new_smb_fname,
				&parent_fname,
				&base_name);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	ret = SMB_VFS_SYMLINKAT(conn,
			&target_fname,
			parent_fname->fsp,
			base_name);
	if (ret != 0) {
		TALLOC_FREE(parent_fname);
		return map_nt_error_from_unix(errno);
	}

	TALLOC_FREE(parent_fname);
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static uint32_t unix_filetype(mode_t mode)
{
	if(S_ISREG(mode))
		return UNIX_TYPE_FILE;
	else if(S_ISDIR(mode))
		return UNIX_TYPE_DIR;
#ifdef S_ISLNK
	else if(S_ISLNK(mode))
		return UNIX_TYPE_SYMLINK;
#endif
#ifdef S_ISCHR
	else if(S_ISCHR(mode))
		return UNIX_TYPE_CHARDEV;
#endif
#ifdef S_ISBLK
	else if(S_ISBLK(mode))
		return UNIX_TYPE_BLKDEV;
#endif
#ifdef S_ISFIFO
	else if(S_ISFIFO(mode))
		return UNIX_TYPE_FIFO;
#endif
#ifdef S_ISSOCK
	else if(S_ISSOCK(mode))
		return UNIX_TYPE_SOCKET;
#endif

	DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
	return UNIX_TYPE_UNKNOWN;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_info_standard(connection_struct *conn,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname)
{
	NTSTATUS status;
	struct smb_file_time ft;

	init_smb_file_time(&ft);

	if (total_data < 12) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp == NULL) {
		return NT_STATUS_INVALID_HANDLE;
	}

	/* create time */
	ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata));
	/* access time */
	ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4));
	/* write time */
	ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8));

	DEBUG(10,("smb_set_info_standard: file %s\n",
		smb_fname_str_dbg(smb_fname)));

	status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (fsp->fsp_flags.modified) {
		trigger_write_time_update_immediate(fsp);
	}
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_posix_acl(connection_struct *conn,
				struct smb_request *req,
				const char *pdata,
				int total_data_in,
				files_struct *fsp,
				struct smb_filename *smb_fname)
{
	uint16_t posix_acl_version;
	uint16_t num_file_acls;
	uint16_t num_def_acls;
	bool valid_file_acls = true;
	bool valid_def_acls = true;
	NTSTATUS status;
	unsigned int size_needed;
	unsigned int total_data;
	bool close_fsp = false;

	if (total_data_in < 0) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	total_data = total_data_in;

	if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}
	posix_acl_version = SVAL(pdata,0);
	num_file_acls = SVAL(pdata,2);
	num_def_acls = SVAL(pdata,4);

	if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
		valid_file_acls = false;
		num_file_acls = 0;
	}

	if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
		valid_def_acls = false;
		num_def_acls = 0;
	}

	if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	/* Wrap checks. */
	if (num_file_acls + num_def_acls < num_file_acls) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	size_needed = num_file_acls + num_def_acls;

	/*
	 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
	 * than UINT_MAX, so check by division.
	 */
	if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
	if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}
	size_needed += SMB_POSIX_ACL_HEADER_SIZE;

	if (total_data < size_needed) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto out;
	}

	/*
	 * Ensure we always operate on a file descriptor, not just
	 * the filename.
	 */
	if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
		uint32_t access_mask = SEC_STD_WRITE_OWNER|
					SEC_STD_WRITE_DAC|
					SEC_STD_READ_CONTROL|
					FILE_READ_ATTRIBUTES|
					FILE_WRITE_ATTRIBUTES;

		status = get_posix_fsp(conn,
					req,
					smb_fname,
					access_mask,
					&fsp);

		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}
		close_fsp = true;
	}

	/* Here we know fsp != NULL */
	SMB_ASSERT(fsp != NULL);

	status = refuse_symlink_fsp(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		goto out;
	}

	/* If we have a default acl, this *must* be a directory. */
	if (valid_def_acls && !fsp->fsp_flags.is_directory) {
		DBG_INFO("Can't set default acls on "
			 "non-directory %s\n",
			 fsp_str_dbg(fsp));
		return NT_STATUS_INVALID_HANDLE;
	}

	DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
		  "num_def_acls = %"PRIu16"\n",
		  fsp_str_dbg(fsp),
		  num_file_acls,
		  num_def_acls);

	/* Move pdata to the start of the file ACL entries. */
	pdata += SMB_POSIX_ACL_HEADER_SIZE;

	if (valid_file_acls) {
		status = set_unix_posix_acl(conn,
					fsp,
					num_file_acls,
					pdata);
		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}
	}

	/* Move pdata to the start of the default ACL entries. */
	pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);

	if (valid_def_acls) {
		status = set_unix_posix_default_acl(conn,
					fsp,
					num_def_acls,
					pdata);
		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}
	}

	status = NT_STATUS_OK;

  out:

	if (close_fsp) {
		(void)close_file(req, fsp, NORMAL_CLOSE);
		fsp = NULL;
	}
	return status;
}

Project: samba
File: trans2.c

static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
	connection_struct *conn, struct ea_list *ea_list)
{
	unsigned int ret_data_size = 4;
	char *p = pdata;

	SMB_ASSERT(total_data_size >= 4);

	if (!lp_ea_support(SNUM(conn))) {
		SIVAL(pdata,4,0);
		return 4;
	}

	for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
		size_t dos_namelen;
		fstring dos_ea_name;
		push_ascii_fstring(dos_ea_name, ea_list->ea.name);
		dos_namelen = strlen(dos_ea_name);
		if (dos_namelen > 255 || dos_namelen == 0) {
			break;
		}
		if (ea_list->ea.value.length > 65535) {
			break;
		}
		if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
			break;
		}

		/* We know we have room. */
		SCVAL(p,0,ea_list->ea.flags);
		SCVAL(p,1,dos_namelen);
		SSVAL(p,2,ea_list->ea.value.length);
		strlcpy(p+4, dos_ea_name, dos_namelen+1);
		if (ea_list->ea.value.length > 0) {
			memcpy(p + 4 + dos_namelen + 1,
			       ea_list->ea.value.data,
			       ea_list->ea.value.length);
		}

		total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
		p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
	}

	ret_data_size = PTR_DIFF(p, pdata);
	DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
	SIVAL(pdata,0,ret_data_size);
	return ret_data_size;
}

Project: samba
File: trans2.c

static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
{
	struct ea_list *ea_list_head = NULL;
	size_t offset = 0;
	size_t bytes_used = 0;

	while (offset < data_size) {
		struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);

		if (!eal) {
			return NULL;
		}

		DLIST_ADD_END(ea_list_head, eal);
		offset += bytes_used;
	}

	return ea_list_head;
}

Project: samba
File: trans2.c

static size_t ea_list_size(struct ea_list *ealist)
{
	fstring dos_ea_name;
	struct ea_list *listp;
	size_t ret = 0;

	for (listp = ealist; listp; listp = listp->next) {
		push_ascii_fstring(dos_ea_name, listp->ea.name);
		ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
	}
	/* Add on 4 for total length. */
	if (ret) {
		ret += 4;
	}

	return ret;
}

Project: samba
File: trans2.c

static void call_trans2setfsinfo(connection_struct *conn,
				 struct smb_request *req,
				 char **pparams, int total_params,
				 char **ppdata, int total_data,
				 unsigned int max_data_bytes)
{
	const struct loadparm_substitution *lp_sub =
		loadparm_s3_global_substitution();
	struct smbXsrv_connection *xconn = req->xconn;
	char *pdata = *ppdata;
	char *params = *pparams;
	uint16_t info_level;

	DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
		  lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));

	/*  */
	if (total_params < 4) {
		DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
			total_params));
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	info_level = SVAL(params,2);

	if (IS_IPC(conn)) {
		if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
				info_level != SMB_SET_CIFS_UNIX_INFO) {
			DEBUG(0,("call_trans2setfsinfo: not an allowed "
				"info level (0x%x) on IPC$.\n",
				(unsigned int)info_level));
			reply_nterror(req, NT_STATUS_ACCESS_DENIED);
			return;
		}
	}

	if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
		if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
			DEBUG(0,("call_trans2setfsinfo: encryption required "
				"and info level 0x%x sent.\n",
				(unsigned int)info_level));
			reply_nterror(req, NT_STATUS_ACCESS_DENIED);
			return;
		}
	}

	switch(info_level) {
		case SMB_SET_CIFS_UNIX_INFO:
			if (!lp_unix_extensions()) {
				DEBUG(2,("call_trans2setfsinfo: "
					"SMB_SET_CIFS_UNIX_INFO is invalid with "
					"unix extensions off\n"));
				reply_nterror(req,
					      NT_STATUS_INVALID_LEVEL);
				return;
			}

			/* There should be 12 bytes of capabilities set. */
			if (total_data < 12) {
				reply_nterror(
					req,
					NT_STATUS_INVALID_PARAMETER);
				return;
			}
			xconn->smb1.unix_info.client_major = SVAL(pdata,0);
			xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
			xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
			xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
			/* Just print these values for now. */
			DEBUG(10, ("call_trans2setfsinfo: set unix_info info. "
				   "major = %u, minor = %u cap_low = 0x%x, "
				   "cap_high = 0x%xn",
				   (unsigned int)xconn->
				   smb1.unix_info.client_major,
				   (unsigned int)xconn->
				   smb1.unix_info.client_minor,
				   (unsigned int)xconn->
				   smb1.unix_info.client_cap_low,
				   (unsigned int)xconn->
				   smb1.unix_info.client_cap_high));

			/* Here is where we must switch to posix pathname processing... */
			if (xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
				lp_set_posix_pathnames();
				mangle_change_to_posix();
			}

			if ((xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
			    !(xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
				/* Client that knows how to do posix locks,
				 * but not posix open/mkdir operations. Set a
				 * default type for read/write checks. */

				lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);

			}
			break;

		case SMB_REQUEST_TRANSPORT_ENCRYPTION:
			{
				NTSTATUS status;
				size_t param_len = 0;
				size_t data_len = total_data;

				if (!lp_unix_extensions()) {
					reply_nterror(
						req,
						NT_STATUS_INVALID_LEVEL);
					return;
				}

				if (lp_server_smb_encrypt(SNUM(conn)) ==
				    SMB_ENCRYPTION_OFF) {
					reply_nterror(
						req,
						NT_STATUS_NOT_SUPPORTED);
					return;
				}

				if (xconn->smb1.echo_handler.trusted_fde) {
					DEBUG( 2,("call_trans2setfsinfo: "
						"request transport encryption disabled"
						"with 'fork echo handler = yes'\n"));
					reply_nterror(
						req,
						NT_STATUS_NOT_SUPPORTED);
					return;
				}

				DEBUG( 4,("call_trans2setfsinfo: "
					"request transport encryption.\n"));

				status = srv_request_encryption_setup(conn,
								(unsigned char **)ppdata,
								&data_len,
								(unsigned char **)pparams,
								&param_len);

				if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
						!NT_STATUS_IS_OK(status)) {
					reply_nterror(req, status);
					return;
				}

				send_trans2_replies(conn, req,
						NT_STATUS_OK,
						*pparams,
						param_len,
						*ppdata,
						data_len,
						max_data_bytes);

				if (NT_STATUS_IS_OK(status)) {
					/* Server-side transport
					 * encryption is now *on*. */
					status = srv_encryption_start(conn);
					if (!NT_STATUS_IS_OK(status)) {
						char *reason = talloc_asprintf(talloc_tos(),
									       "Failure in setting "
									       "up encrypted transport: %s",
									       nt_errstr(status));
						exit_server_cleanly(reason);
					}
				}
				return;
			}

		case SMB_FS_QUOTA_INFORMATION:
			{
				NTSTATUS status;
				DATA_BLOB qdata = {
						.data = (uint8_t *)pdata,
						.length = total_data
				};
				files_struct *fsp = NULL;
				fsp = file_fsp(req, SVAL(params,0));

				status = smb_set_fsquota(conn,
							req,
							fsp,
							&qdata);
				if (!NT_STATUS_IS_OK(status)) {
					reply_nterror(req, status);
					return;
				}
				break;
			}
		default:
			DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
				info_level));
			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
			return;
			break;
	}

	/* 
	 * sending this reply works fine, 
	 * but I'm not sure it's the same 
	 * like windows do...
	 * --metze
	 */
	reply_outbuf(req, 10, 0);
}

Project: samba
File: trans2.c

void reply_findclose(struct smb_request *req)
{
	int dptr_num;
	struct smbd_server_connection *sconn = req->sconn;
	files_struct *fsp = NULL;

	START_PROFILE(SMBfindclose);

	if (req->wct < 1) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		END_PROFILE(SMBfindclose);
		return;
	}

	dptr_num = SVALS(req->vwv+0, 0);

	DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));

	/*
	 * OS/2 seems to use -1 to indicate "close all directories"
	 * This has to mean on this specific connection struct.
	 */
	if (dptr_num == -1) {
		dptr_closecnum(req->conn);
	} else {
		fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
		dptr_num = -1;
		if (fsp != NULL) {
			close_file(NULL, fsp, NORMAL_CLOSE);
			fsp = NULL;
		}
	}

	reply_outbuf(req, 0, 0);

	DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));

	END_PROFILE(SMBfindclose);
	return;
}

Project: samba
File: trans2.c

void reply_findnclose(struct smb_request *req)
{
	int dptr_num;

	START_PROFILE(SMBfindnclose);

	if (req->wct < 1) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		END_PROFILE(SMBfindnclose);
		return;
	}

	dptr_num = SVAL(req->vwv+0, 0);

	DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));

	/* We never give out valid handles for a 
	   findnotifyfirst - so any dptr_num is ok here. 
	   Just ignore it. */

	reply_outbuf(req, 0, 0);

	DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));

	END_PROFILE(SMBfindnclose);
	return;
}

Project: samba
File: trans2.c

static void call_trans2open(connection_struct *conn,
			    struct smb_request *req,
			    char **pparams, int total_params,
			    char **ppdata, int total_data,
			    unsigned int max_data_bytes)
{
	struct smb_filename *smb_fname = NULL;
	char *params = *pparams;
	char *pdata = *ppdata;
	int deny_mode;
	int32_t open_attr;
	bool oplock_request;
#if 0
	bool return_additional_info;
	int16 open_sattr;
	time_t open_time;
#endif
	int open_ofun;
	uint32_t open_size;
	char *pname;
	char *fname = NULL;
	off_t size=0;
	int fattr=0,mtime=0;
	SMB_INO_T inode = 0;
	int smb_action = 0;
	files_struct *fsp;
	struct ea_list *ea_list = NULL;
	uint16_t flags = 0;
	NTSTATUS status;
	uint32_t access_mask;
	uint32_t share_mode;
	uint32_t create_disposition;
	uint32_t create_options = 0;
	uint32_t private_flags = 0;
	uint32_t ucf_flags = ucf_flags_from_smb_request(req);
	TALLOC_CTX *ctx = talloc_tos();

	/*
	 * Ensure we have enough parameters to perform the operation.
	 */

	if (total_params < 29) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		goto out;
	}

	flags = SVAL(params, 0);
	deny_mode = SVAL(params, 2);
	open_attr = SVAL(params,6);
        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
        if (oplock_request) {
                oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
        }

#if 0
	return_additional_info = BITSETW(params,0);
	open_sattr = SVAL(params, 4);
	open_time = make_unix_date3(params+8);
#endif
	open_ofun = SVAL(params,12);
	open_size = IVAL(params,14);
	pname = &params[28];

	if (IS_IPC(conn)) {
		reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
		goto out;
	}

	if (req->posix_pathnames) {
		srvstr_get_path_posix(ctx,
			params,
			req->flags2,
			&fname,
			pname,
			total_params - 28,
			STR_TERMINATE,
			&status);
	} else {
		srvstr_get_path(ctx,
			params,
			req->flags2,
			&fname,
			pname,
			total_params - 28,
			STR_TERMINATE,
			&status);
	}
	if (!NT_STATUS_IS_OK(status)) {
		reply_nterror(req, status);
		goto out;
	}

	DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
		fname, (unsigned int)deny_mode, (unsigned int)open_attr,
		(unsigned int)open_ofun, open_size));

	status = filename_convert(ctx,
				conn,
				fname,
				ucf_flags,
				0,
				&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,
				ERRSRV, ERRbadpath);
			goto out;
		}
		reply_nterror(req, status);
		goto out;
	}

	if (open_ofun == 0) {
		reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
		goto out;
	}

	if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
					 open_ofun,
					 &access_mask, &share_mode,
					 &create_disposition,
					 &create_options,
					 &private_flags)) {
		reply_nterror(req, NT_STATUS_ACCESS_DENIED);
		goto out;
	}

	/* Any data in this call is an EA list. */
	if (total_data && (total_data != 4)) {
		if (total_data < 10) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}

		if (IVAL(pdata,0) > total_data) {
			DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
				IVAL(pdata,0), (unsigned int)total_data));
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}

		ea_list = read_ea_list(talloc_tos(), pdata + 4,
				       total_data - 4);
		if (!ea_list) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}

		if (!lp_ea_support(SNUM(conn))) {
			reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
			goto out;
		}

		if (!req->posix_pathnames &&
				ea_list_has_invalid_name(ea_list)) {
			int param_len = 30;
			*pparams = (char *)SMB_REALLOC(*pparams, param_len);
			if(*pparams == NULL ) {
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				goto out;
			}
			params = *pparams;
			memset(params, '\0', param_len);
			send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
				params, param_len, NULL, 0, max_data_bytes);
			goto out;
		}
	}

	status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		access_mask,				/* access_mask */
		share_mode,				/* share_access */
		create_disposition,			/* create_disposition*/
		create_options,				/* create_options */
		open_attr,				/* file_attributes */
		oplock_request,				/* oplock_request */
		NULL,					/* lease */
		open_size,				/* allocation_size */
		private_flags,
		NULL,					/* sd */
		ea_list,				/* ea_list */
		&fsp,					/* result */
		&smb_action,				/* psbuf */
		NULL, NULL);				/* create context */

	if (!NT_STATUS_IS_OK(status)) {
		if (open_was_deferred(req->xconn, req->mid)) {
			/* We have re-scheduled this call. */
			goto out;
		}

		if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
			reply_openerror(req, status);
			goto out;
		}

		fsp = fcb_or_dos_open(
			req,
			smb_fname,
			access_mask,
			create_options,
			private_flags);
		if (fsp == NULL) {
			bool ok = defer_smb1_sharing_violation(req);
			if (ok) {
				goto out;
			}
			reply_openerror(req, status);
			goto out;
		}

		smb_action = FILE_WAS_OPENED;
	}

	size = get_file_size_stat(&smb_fname->st);
	fattr = fdos_mode(fsp);
	mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
	inode = smb_fname->st.st_ex_ino;
	if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
		close_file(req, fsp, ERROR_CLOSE);
		reply_nterror(req, NT_STATUS_ACCESS_DENIED);
		goto out;
	}

	/* Realloc the size of parameters and data we will return */
	*pparams = (char *)SMB_REALLOC(*pparams, 30);
	if(*pparams == NULL ) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		goto out;
	}
	params = *pparams;

	SSVAL(params,0,fsp->fnum);
	SSVAL(params,2,fattr);
	srv_put_dos_date2(params,4, mtime);
	SIVAL(params,8, (uint32_t)size);
	SSVAL(params,12,deny_mode);
	SSVAL(params,14,0); /* open_type - file or directory. */
	SSVAL(params,16,0); /* open_state - only valid for IPC device. */

	if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
		smb_action |= EXTENDED_OPLOCK_GRANTED;
	}

	SSVAL(params,18,smb_action);

	/*
	 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
	 */
	SIVAL(params,20,inode);
	SSVAL(params,24,0); /* Padding. */
	if (flags & 8) {
		uint32_t ea_size = estimate_ea_size(smb_fname->fsp);
		SIVAL(params, 26, ea_size);
	} else {
		SIVAL(params, 26, 0);
	}

	/* Send the required number of replies */
	send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
 out:
	TALLOC_FREE(smb_fname);
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_size(connection_struct *conn,
				  struct smb_request *req,
				  files_struct *fsp,
				  struct smb_filename *smb_fname,
				  const SMB_STRUCT_STAT *psbuf,
				  off_t size,
				  bool fail_after_createfile)
{
	NTSTATUS status = NT_STATUS_OK;
	files_struct *new_fsp = NULL;

	if (!VALID_STAT(*psbuf)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	DBG_INFO("size: %"PRIu64", file_size_stat=%"PRIu64"\n",
		 (uint64_t)size,
		 get_file_size_stat(psbuf));

	if (size == get_file_size_stat(psbuf)) {
		if (fsp == NULL) {
			return NT_STATUS_OK;
		}
		if (!fsp->fsp_flags.modified) {
			return NT_STATUS_OK;
		}
		trigger_write_time_update_immediate(fsp);
		return NT_STATUS_OK;
	}

	DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
		  smb_fname_str_dbg(smb_fname), (double)size));

	if (fsp &&
	    !fsp->fsp_flags.is_pathref &&
	    fsp_get_io_fd(fsp) != -1)
	{
		/* Handle based call. */
		if (!(fsp->access_mask & FILE_WRITE_DATA)) {
			return NT_STATUS_ACCESS_DENIED;
		}

		if (vfs_set_filelen(fsp, size) == -1) {
			return map_nt_error_from_unix(errno);
		}
		trigger_write_time_update_immediate(fsp);
		return NT_STATUS_OK;
	}

        status = SMB_VFS_CREATE_FILE(
		conn,					/* conn */
		req,					/* req */
		smb_fname,				/* fname */
		FILE_WRITE_DATA,			/* access_mask */
		(FILE_SHARE_READ | FILE_SHARE_WRITE |	/* share_access */
		    FILE_SHARE_DELETE),
		FILE_OPEN,				/* create_disposition*/
		0,					/* create_options */
		FILE_ATTRIBUTE_NORMAL,			/* file_attributes */
		0,					/* oplock_request */
		NULL,					/* lease */
		0,					/* allocation_size */
		0,					/* private_flags */
		NULL,					/* sd */
		NULL,					/* ea_list */
		&new_fsp,				/* result */
		NULL,					/* pinfo */
		NULL, NULL);				/* create context */

	if (!NT_STATUS_IS_OK(status)) {
		/* NB. We check for open_was_deferred in the caller. */
		return status;
	}

	/* See RAW-SFILEINFO-END-OF-FILE */
	if (fail_after_createfile) {
		close_file(req, new_fsp,NORMAL_CLOSE);
		return NT_STATUS_INVALID_LEVEL;
	}

	if (vfs_set_filelen(new_fsp, size) == -1) {
		status = map_nt_error_from_unix(errno);
		close_file(req, new_fsp,NORMAL_CLOSE);
		return status;
	}

	trigger_write_time_update_immediate(new_fsp);
	close_file(req, new_fsp,NORMAL_CLOSE);
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

void reply_transs2(struct smb_request *req)
{
	connection_struct *conn = req->conn;
	unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
	struct trans_state *state;

	START_PROFILE(SMBtranss2);

	show_msg((const char *)req->inbuf);

	/* Windows clients expect all replies to
	   a transact secondary (SMBtranss2 0x33)
	   to have a command code of transact
	   (SMBtrans2 0x32). See bug #8989
	   and also [MS-CIFS] section 2.2.4.47.2
	   for details.
	*/
	req->cmd = SMBtrans2;

	if (req->wct < 8) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		END_PROFILE(SMBtranss2);
		return;
	}

	for (state = conn->pending_trans; state != NULL;
	     state = state->next) {
		if (state->mid == req->mid) {
			break;
		}
	}

	if ((state == NULL) || (state->cmd != SMBtrans2)) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		END_PROFILE(SMBtranss2);
		return;
	}

	/* Revise state->total_param and state->total_data in case they have
	   changed downwards */

	if (SVAL(req->vwv+0, 0) < state->total_param)
		state->total_param = SVAL(req->vwv+0, 0);
	if (SVAL(req->vwv+1, 0) < state->total_data)
		state->total_data = SVAL(req->vwv+1, 0);

	pcnt = SVAL(req->vwv+2, 0);
	poff = SVAL(req->vwv+3, 0);
	pdisp = SVAL(req->vwv+4, 0);

	dcnt = SVAL(req->vwv+5, 0);
	doff = SVAL(req->vwv+6, 0);
	ddisp = SVAL(req->vwv+7, 0);

	state->received_param += pcnt;
	state->received_data += dcnt;

	if ((state->received_data > state->total_data) ||
	    (state->received_param > state->total_param))
		goto bad_param;

	if (pcnt) {
		if (trans_oob(state->total_param, pdisp, pcnt)
		    || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
			goto bad_param;
		}
		memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
	}

	if (dcnt) {
		if (trans_oob(state->total_data, ddisp, dcnt)
		    || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
			goto bad_param;
		}
		memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
	}

	if ((state->received_param < state->total_param) ||
	    (state->received_data < state->total_data)) {
		END_PROFILE(SMBtranss2);
		return;
	}

	handle_trans2(conn, req, state);

	DLIST_REMOVE(conn->pending_trans, state);
	SAFE_FREE(state->data);
	SAFE_FREE(state->param);
	TALLOC_FREE(state);

	END_PROFILE(SMBtranss2);
	return;

  bad_param:

	DEBUG(0,("reply_transs2: invalid trans parameters\n"));
	DLIST_REMOVE(conn->pending_trans, state);
	SAFE_FREE(state->data);
	SAFE_FREE(state->param);
	TALLOC_FREE(state);
	reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
	END_PROFILE(SMBtranss2);
	return;
}

Project: samba
File: trans2.c

static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
				uint32_t *smb_fflags, uint32_t *smb_fmask)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
	    *smb_fmask |= info2_flags_map[i].smb_fflag;
	    if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
		    *smb_fflags |= info2_flags_map[i].smb_fflag;
	    }
	}
}

Project: samba
File: trans2.c

static NTSTATUS smb_file_mode_information(connection_struct *conn,
				const char *pdata,
				int total_data)
{
	uint32_t mode;

	if (total_data < 4) {
		return NT_STATUS_INVALID_PARAMETER;
	}
	mode = IVAL(pdata,0);
	if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
		return NT_STATUS_INVALID_PARAMETER;
	}
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
					 void *private_data,
					 const char *dname,
					 const char *mask,
					 char **_fname)
{
	struct smbd_dirptr_lanman2_state *state =
		(struct smbd_dirptr_lanman2_state *)private_data;
	bool ok;
	char mangled_name[13]; /* mangled 8.3 name. */
	bool got_match;
	const char *fname;

	/* Mangle fname if it's an illegal name. */
	if (mangle_must_mangle(dname, state->conn->params)) {
		/*
		 * Slow path - ensure we can push the original name as UCS2. If
		 * not, then just don't return this name.
		 */
		NTSTATUS status;
		size_t ret_len = 0;
		size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
		uint8_t *tmp = talloc_array(talloc_tos(),
					uint8_t,
					len);

		status = srvstr_push(NULL,
			FLAGS2_UNICODE_STRINGS,
			tmp,
			dname,
			len,
			STR_TERMINATE,
			&ret_len);

		TALLOC_FREE(tmp);

		if (!NT_STATUS_IS_OK(status)) {
			return false;
		}

		ok = name_to_8_3(dname, mangled_name,
				 true, state->conn->params);
		if (!ok) {
			return false;
		}
		fname = mangled_name;
	} else {
		fname = dname;
	}

	got_match = exact_match(state->has_wild,
				state->conn->case_sensitive,
				fname, mask);
	state->got_exact_match = got_match;
	if (!got_match) {
		got_match = mask_match(fname, mask,
				       state->conn->case_sensitive);
	}

	if(!got_match && state->check_mangled_names &&
	   !mangle_is_8_3(fname, false, state->conn->params)) {
		/*
		 * It turns out that NT matches wildcards against
		 * both long *and* short names. This may explain some
		 * of the wildcard wierdness from old DOS clients
		 * that some people have been seeing.... JRA.
		 */
		/* Force the mangling into 8.3. */
		ok = name_to_8_3(fname, mangled_name,
				 false, state->conn->params);
		if (!ok) {
			return false;
		}

		got_match = exact_match(state->has_wild,
					state->conn->case_sensitive,
					mangled_name, mask);
		state->got_exact_match = got_match;
		if (!got_match) {
			got_match = mask_match(mangled_name, mask,
					       state->conn->case_sensitive);
		}
	}

	if (!got_match) {
		return false;
	}

	*_fname = talloc_strdup(ctx, fname);
	if (*_fname == NULL) {
		return false;
	}

	return true;
}

Project: samba
File: trans2.c

static void call_trans2qfsinfo(connection_struct *conn,
			       struct smb_request *req,
			       char **pparams, int total_params,
			       char **ppdata, int total_data,
			       unsigned int max_data_bytes)
{
	char *params = *pparams;
	uint16_t info_level;
	int data_len = 0;
	size_t fixed_portion;
	NTSTATUS status;

	if (total_params < 2) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	info_level = SVAL(params,0);

	if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
		if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
			DEBUG(0,("call_trans2qfsinfo: encryption required "
				"and info level 0x%x sent.\n",
				(unsigned int)info_level));
			reply_nterror(req, NT_STATUS_ACCESS_DENIED);
			return;
		}
	}

	DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));

	status = smbd_do_qfsinfo(req->xconn, conn, req,
				 info_level,
				 req->flags2,
				 max_data_bytes,
				 &fixed_portion,
				 NULL,
				 ppdata, &data_len);
	if (!NT_STATUS_IS_OK(status)) {
		reply_nterror(req, status);
		return;
	}

	send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
			    max_data_bytes);

	DEBUG( 4, ( "%s info_level = %d\n",
		    smb_fn_name(req->cmd), info_level) );

	return;
}

Project: samba
File: trans2.c

NTSTATUS unix_perms_from_wire(connection_struct *conn,
			      const SMB_STRUCT_STAT *psbuf,
			      uint32_t perms,
			      enum perm_type ptype,
			      mode_t *ret_perms)
{
	mode_t ret = 0;

	if (perms == SMB_MODE_NO_CHANGE) {
		if (!VALID_STAT(*psbuf)) {
			return NT_STATUS_INVALID_PARAMETER;
		} else {
			*ret_perms = psbuf->st_ex_mode;
			return NT_STATUS_OK;
		}
	}

	ret = wire_perms_to_unix(perms);

	if (ptype == PERM_NEW_FILE) {
		/*
		 * "create mask"/"force create mode" are
		 * only applied to new files, not existing ones.
		 */
		ret &= lp_create_mask(SNUM(conn));
		/* Add in force bits */
		ret |= lp_force_create_mode(SNUM(conn));
	} else if (ptype == PERM_NEW_DIR) {
		/*
		 * "directory mask"/"force directory mode" are
		 * only applied to new directories, not existing ones.
		 */
		ret &= lp_directory_mask(SNUM(conn));
		/* Add in force bits */
		ret |= lp_force_directory_mode(SNUM(conn));
	}

	*ret_perms = ret;
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

NTSTATUS smbd_do_setfsinfo(connection_struct *conn,
                                struct smb_request *req,
                                TALLOC_CTX *mem_ctx,
                                uint16_t info_level,
                                files_struct *fsp,
				const DATA_BLOB *pdata)
{
	switch (info_level) {
		case SMB_FS_QUOTA_INFORMATION:
		{
			return smb_set_fsquota(conn,
						req,
						fsp,
						pdata);
		}

		default:
			break;
	}
	return NT_STATUS_INVALID_LEVEL;
}

Project: samba
File: trans2.c

NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
				struct smb_request *req,
				TALLOC_CTX *mem_ctx,
				uint16_t info_level,
				files_struct *fsp,
				struct smb_filename *smb_fname,
				char **ppdata, int total_data,
				int *ret_data_size)
{
	char *pdata = *ppdata;
	NTSTATUS status = NT_STATUS_OK;
	int data_return_size = 0;

	if (INFO_LEVEL_IS_UNIX(info_level)) {
		if (!lp_unix_extensions()) {
			return NT_STATUS_INVALID_LEVEL;
		}

		status = smbd_do_posix_setfilepathinfo(conn,
						       req,
						       req,
						       info_level,
						       smb_fname,
						       fsp,
						       ppdata,
						       total_data,
						       &data_return_size);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		*ret_data_size = data_return_size;
		return NT_STATUS_OK;
	}

	*ret_data_size = 0;

	DEBUG(3,("smbd_do_setfilepathinfo: %s (%s) info_level=%d "
		 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
		 fsp_fnum_dbg(fsp),
		 info_level, total_data));

	switch (info_level) {

		case SMB_INFO_STANDARD:
		{
			status = smb_set_info_standard(conn,
					pdata,
					total_data,
					fsp,
					smb_fname);
			break;
		}

		case SMB_INFO_SET_EA:
		{
			status = smb_info_set_ea(conn,
						pdata,
						total_data,
						fsp,
						smb_fname);
			break;
		}

		case SMB_SET_FILE_BASIC_INFO:
		case SMB_FILE_BASIC_INFORMATION:
		{
			status = smb_set_file_basic_info(conn,
							pdata,
							total_data,
							fsp,
							smb_fname);
			break;
		}

		case SMB_FILE_ALLOCATION_INFORMATION:
		case SMB_SET_FILE_ALLOCATION_INFO:
		{
			status = smb_set_file_allocation_info(conn, req,
								pdata,
								total_data,
								fsp,
								smb_fname);
			break;
		}

		case SMB_FILE_END_OF_FILE_INFORMATION:
		case SMB_SET_FILE_END_OF_FILE_INFO:
		{
			/*
			 * XP/Win7 both fail after the createfile with
			 * SMB_SET_FILE_END_OF_FILE_INFO but not
			 * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
			 * The level is known here, so pass it down
			 * appropriately.
			 */
			bool should_fail =
			    (info_level == SMB_SET_FILE_END_OF_FILE_INFO);

			status = smb_set_file_end_of_file_info(conn, req,
								pdata,
								total_data,
								fsp,
								smb_fname,
								should_fail);
			break;
		}

		case SMB_FILE_DISPOSITION_INFORMATION:
		case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
		{
#if 0
			/* JRA - We used to just ignore this on a path ? 
			 * Shouldn't this be invalid level on a pathname
			 * based call ?
			 */
			if (tran_call != TRANSACT2_SETFILEINFO) {
				return ERROR_NT(NT_STATUS_INVALID_LEVEL);
			}
#endif
			status = smb_set_file_disposition_info(conn,
						pdata,
						total_data,
						fsp,
						smb_fname);
			break;
		}

		case SMB_FILE_POSITION_INFORMATION:
		{
			status = smb_file_position_information(conn,
						pdata,
						total_data,
						fsp);
			break;
		}

		case SMB_FILE_FULL_EA_INFORMATION:
		{
			status = smb_set_file_full_ea_info(conn,
						pdata,
						total_data,
						fsp);
			break;
		}

		/* From tridge Samba4 : 
		 * MODE_INFORMATION in setfileinfo (I have no
		 * idea what "mode information" on a file is - it takes a value of 0,
		 * 2, 4 or 6. What could it be?).
		 */

		case SMB_FILE_MODE_INFORMATION:
		{
			status = smb_file_mode_information(conn,
						pdata,
						total_data);
			break;
		}

		/* [MS-SMB2] 3.3.5.21.1 states we MUST fail with STATUS_NOT_SUPPORTED. */
		case SMB_FILE_VALID_DATA_LENGTH_INFORMATION:
		case SMB_FILE_SHORT_NAME_INFORMATION:
			return NT_STATUS_NOT_SUPPORTED;

		case SMB_FILE_RENAME_INFORMATION:
		{
			status = smb_file_rename_information(conn, req,
							     pdata, total_data,
							     fsp, smb_fname);
			break;
		}

		case SMB2_FILE_RENAME_INFORMATION_INTERNAL:
		{
			/* SMB2 rename information. */
			status = smb2_file_rename_information(conn, req,
							     pdata, total_data,
							     fsp, smb_fname);
			break;
		}

		case SMB_FILE_LINK_INFORMATION:
		{
			status = smb_file_link_information(conn, req,
							pdata, total_data,
							fsp, smb_fname);
			break;
		}

		default:
			return NT_STATUS_INVALID_LEVEL;
	}

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	*ret_data_size = data_return_size;
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_posix_lock(connection_struct *conn,
				struct smb_request *req,
				const char *pdata,
				int total_data,
				files_struct *fsp)
{
	struct tevent_req *subreq = NULL;
	struct smbd_lock_element *lck = NULL;
	uint64_t count;
	uint64_t offset;
	uint64_t smblctx;
	bool blocking_lock = False;
	enum brl_type lock_type;

	NTSTATUS status = NT_STATUS_OK;

	if (fsp == NULL ||
	    fsp->fsp_flags.is_pathref ||
	    fsp_get_io_fd(fsp) == -1)
	{
		return NT_STATUS_INVALID_HANDLE;
	}

	if (total_data != POSIX_LOCK_DATA_SIZE) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
		case POSIX_LOCK_TYPE_READ:
			lock_type = READ_LOCK;
			break;
		case POSIX_LOCK_TYPE_WRITE:
			/* Return the right POSIX-mappable error code for files opened read-only. */
			if (!fsp->fsp_flags.can_write) {
				return NT_STATUS_INVALID_HANDLE;
			}
			lock_type = WRITE_LOCK;
			break;
		case POSIX_LOCK_TYPE_UNLOCK:
			lock_type = UNLOCK_LOCK;
			break;
		default:
			return NT_STATUS_INVALID_PARAMETER;
	}

	switch (SVAL(pdata, POSIX_LOCK_FLAGS_OFFSET)) {
	case POSIX_LOCK_FLAG_NOWAIT:
		blocking_lock = false;
		break;
	case POSIX_LOCK_FLAG_WAIT:
		blocking_lock = true;
		break;
	default:
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!lp_blocking_locks(SNUM(conn))) { 
		blocking_lock = False;
	}

	smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
	offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
			((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
	count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
			((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));

	DBG_DEBUG("file %s, lock_type = %u, smblctx = %"PRIu64", "
		  "count = %"PRIu64", offset = %"PRIu64"\n",
		  fsp_str_dbg(fsp),
		  (unsigned int)lock_type,
		  smblctx,
		  count,
		  offset);

	if (lock_type == UNLOCK_LOCK) {
		struct smbd_lock_element l = {
			.req_guid = smbd_request_guid(req, 0),
			.smblctx = smblctx,
			.brltype = UNLOCK_LOCK,
			.offset = offset,
			.count = count,
		};
		status = smbd_do_unlocking(req, fsp, 1, &l, POSIX_LOCK);
		return status;
	}

	lck = talloc(req, struct smbd_lock_element);
	if (lck == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	*lck = (struct smbd_lock_element) {
		.req_guid = smbd_request_guid(req, 0),
		.smblctx = smblctx,
		.brltype = lock_type,
		.count = count,
		.offset = offset,
	};

	subreq = smbd_smb1_do_locks_send(
		fsp,
		req->sconn->ev_ctx,
		&req,
		fsp,
		blocking_lock ? UINT32_MAX : 0,
		true,		/* large_offset */
		POSIX_LOCK,
		1,
		lck);
	if (subreq == NULL) {
		TALLOC_FREE(lck);
		return NT_STATUS_NO_MEMORY;
	}
	tevent_req_set_callback(subreq, smb_set_posix_lock_done, req);
	return NT_STATUS_EVENT_PENDING;
}

Project: samba
File: trans2.c

static void call_trans2findfirst(connection_struct *conn,
				 struct smb_request *req,
				 char **pparams, int total_params,
				 char **ppdata, int total_data,
				 unsigned int max_data_bytes)
{
	/* We must be careful here that we don't return more than the
		allowed number of data bytes. If this means returning fewer than
		maxentries then so be it. We assume that the redirector has
		enough room for the fixed number of parameter bytes it has
		requested. */
	struct smb_filename *smb_dname = NULL;
	char *params = *pparams;
	char *pdata = *ppdata;
	char *data_end;
	uint32_t dirtype;
	int maxentries;
	uint16_t findfirst_flags;
	bool close_after_first;
	bool close_if_end;
	bool requires_resume_key;
	int info_level;
	char *directory = NULL;
	char *mask = NULL;
	char *p;
	int last_entry_off=0;
	int dptr_num = -1;
	int numentries = 0;
	int i;
	bool finished = False;
	bool dont_descend = False;
	bool out_of_space = False;
	int space_remaining;
	struct ea_list *ea_list = NULL;
	NTSTATUS ntstatus = NT_STATUS_OK;
	bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
	struct smbd_server_connection *sconn = req->sconn;
	uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
			ucf_flags_from_smb_request(req);
	bool backup_priv = false;
	bool as_root = false;
	files_struct *fsp = NULL;
	const struct loadparm_substitution *lp_sub =
		loadparm_s3_global_substitution();
	int ret;

	if (total_params < 13) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		goto out;
	}

	dirtype = SVAL(params,0);
	maxentries = SVAL(params,2);
	findfirst_flags = SVAL(params,4);
	close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
	close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
	requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
	backup_priv = ((findfirst_flags & FLAG_TRANS2_FIND_BACKUP_INTENT) &&
				security_token_has_privilege(get_current_nttok(conn),
						SEC_PRIV_BACKUP));

	info_level = SVAL(params,6);

	DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_data_bytes = %d\n",
		(unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
		(int)backup_priv,
		info_level, max_data_bytes));

	if (!maxentries) {
		/* W2K3 seems to treat zero as 1. */
		maxentries = 1;
	}

	switch (info_level) {
		case SMB_FIND_INFO_STANDARD:
		case SMB_FIND_EA_SIZE:
		case SMB_FIND_EA_LIST:
		case SMB_FIND_FILE_DIRECTORY_INFO:
		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		case SMB_FIND_FILE_NAMES_INFO:
		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
			break;
		case SMB_FIND_FILE_UNIX:
		case SMB_FIND_FILE_UNIX_INFO2:
			if (!lp_unix_extensions()) {
				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
				goto out;
			}
			break;
		default:
			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
			goto out;
	}

	if (req->posix_pathnames) {
		/* Always use filesystem for UNIX mtime query. */
		ask_sharemode = false;
	}

	if (req->posix_pathnames) {
		srvstr_get_path_posix(talloc_tos(),
				params,
				req->flags2,
				&directory,
				params+12,
				total_params - 12,
				STR_TERMINATE,
				&ntstatus);
	} else {
		srvstr_get_path(talloc_tos(),
				params,
				req->flags2,
				&directory,
				params+12,
				total_params - 12,
				STR_TERMINATE,
				&ntstatus);
	}
	if (!NT_STATUS_IS_OK(ntstatus)) {
		reply_nterror(req, ntstatus);
		goto out;
	}

	if (backup_priv) {
		become_root();
		as_root = true;
		ntstatus = filename_convert_with_privilege(talloc_tos(),
				conn,
				req,
				directory,
				ucf_flags,
				&smb_dname);
	} else {
		ntstatus = filename_convert(talloc_tos(), conn,
				    directory,
				    ucf_flags,
				    0,
				    &smb_dname);
	}

	if (!NT_STATUS_IS_OK(ntstatus)) {
		if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
			reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
					ERRSRV, ERRbadpath);
			goto out;
		}
		reply_nterror(req, ntstatus);
		goto out;
	}

	/*
	 * The above call to filename_convert() is on the path from the client
	 * including the search mask. Until the code that chops of the search
	 * mask from the path below is moved before the call to
	 * filename_convert(), we close a possible pathref fsp to ensure
	 * SMB_VFS_CREATE_FILE() below will internally open a pathref fsp on the
	 * correct path.
	 */
	if (smb_dname->fsp != NULL) {
		ntstatus = fd_close(smb_dname->fsp);
		if (!NT_STATUS_IS_OK(ntstatus)) {
			reply_nterror(req, ntstatus);
			goto out;
		}
		/*
		 * The pathref fsp link destructor will set smb_dname->fsp to
		 * NULL. Turning this into an assert to give a hint at readers
		 * of the code trying to understand the mechanics.
		 */
		file_free(req, smb_dname->fsp);
		SMB_ASSERT(smb_dname->fsp == NULL);
	}

	mask = get_original_lcomp(talloc_tos(),
				conn,
				directory,
				ucf_flags);
	if (mask == NULL) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		goto out;
	}

	directory = smb_dname->base_name;

	p = strrchr_m(directory,'/');
	if(p == NULL) {
		/* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
		if((directory[0] == '.') && (directory[1] == '\0')) {
			mask = talloc_strdup(talloc_tos(),"*");
			if (!mask) {
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				goto out;
			}
		}
	} else {
		*p = 0;
	}

	if (p == NULL || p == directory) {
		struct smb_filename *old_name = smb_dname;

		/* Ensure we don't have a directory name of "". */
		smb_dname = synthetic_smb_fname(talloc_tos(),
						".",
						NULL,
						&old_name->st,
						old_name->twrp,
						old_name->flags);
		TALLOC_FREE(old_name);
		if (smb_dname == NULL) {
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			goto out;
		}
		directory = smb_dname->base_name;
	}

	DEBUG(5,("dir=%s, mask = %s\n",directory, mask));

	if (info_level == SMB_FIND_EA_LIST) {
		uint32_t ea_size;

		if (total_data < 4) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}

		ea_size = IVAL(pdata,0);
		if (ea_size != total_data) {
			DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}

		if (!lp_ea_support(SNUM(conn))) {
			reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
			goto out;
		}

		/* Pull out the list of names. */
		ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4);
		if (!ea_list) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			goto out;
		}
	}

	if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		goto out;
	}

	*ppdata = (char *)SMB_REALLOC(
		*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
	if(*ppdata == NULL ) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		goto out;
	}
	pdata = *ppdata;
	data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
	/*
	 * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
	 * error.
	 */
	memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
	/* Realloc the params space */
	*pparams = (char *)SMB_REALLOC(*pparams, 10);
	if (*pparams == NULL) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		goto out;
	}
	params = *pparams;

	/*
	 * As we've cut off the last component from
	 * smb_fname we need to re-stat smb_dname
	 * so FILE_OPEN disposition knows the directory
	 * exists.
	 */
	ret = vfs_stat(conn, smb_dname);
	if (ret == -1) {
		ntstatus = map_nt_error_from_unix(errno);
		reply_nterror(req, ntstatus);
		goto out;
	}

	ntstatus = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
	if (!NT_STATUS_IS_OK(ntstatus)) {
		reply_nterror(req, ntstatus);
		goto out;
	}

	/*
	 * Open an fsp on this directory for the dptr.
	 */
	ntstatus = SMB_VFS_CREATE_FILE(
			conn, /* conn */
			req, /* req */
			smb_dname, /* dname */
			FILE_LIST_DIRECTORY, /* access_mask */
			FILE_SHARE_READ|
			FILE_SHARE_WRITE, /* share_access */
			FILE_OPEN, /* create_disposition*/
			FILE_DIRECTORY_FILE, /* create_options */
			FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
			NO_OPLOCK, /* oplock_request */
			NULL, /* lease */
			0, /* allocation_size */
			0, /* private_flags */
			NULL, /* sd */
			NULL, /* ea_list */
			&fsp, /* result */
			NULL, /* pinfo */
			NULL, /* in_context */
			NULL);/* out_context */

	if (!NT_STATUS_IS_OK(ntstatus)) {
		DBG_ERR("failed to open directory %s\n",
			smb_fname_str_dbg(smb_dname));
		reply_nterror(req, ntstatus);
		goto out;
	}

	/* Save the wildcard match and attribs we are using on this directory -
		needed as lanman2 assumes these are being saved between calls */

	ntstatus = dptr_create(conn,
				req,
				fsp, /* fsp */
				False,
				True,
				req->smbpid,
				mask,
				dirtype,
				&fsp->dptr);

	if (!NT_STATUS_IS_OK(ntstatus)) {
		/*
		 * Use NULL here for the first parameter (req)
		 * as this is not a client visible handle so
		 * can'tbe part of an SMB1 chain.
		 */
		close_file(NULL, fsp, NORMAL_CLOSE);
		fsp = NULL;
		reply_nterror(req, ntstatus);
		goto out;
	}

	if (backup_priv) {
		/* Remember this in case we have
		   to do a findnext. */
		dptr_set_priv(fsp->dptr);
	}

	dptr_num = dptr_dnum(fsp->dptr);
	DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));

	/* We don't need to check for VOL here as this is returned by
		a different TRANS2 call. */

	DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
		 directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
	if (in_list(directory,
		    lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
			conn->case_sensitive)) {
		dont_descend = True;
	}

	p = pdata;
	space_remaining = max_data_bytes;
	out_of_space = False;

	for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
		bool got_exact_match = False;

		/* this is a heuristic to avoid seeking the dirptr except when
			absolutely necessary. It allows for a filename of about 40 chars */
		if (space_remaining < DIRLEN_GUESS && numentries > 0) {
			out_of_space = True;
			finished = False;
		} else {
			ntstatus = get_lanman2_dir_entry(talloc_tos(),
					conn,
					fsp->dptr,
					req->flags2,
					mask,dirtype,info_level,
					requires_resume_key,dont_descend,
					ask_sharemode,
					&p,pdata,data_end,
					space_remaining,
					&got_exact_match,
					&last_entry_off, ea_list);
			if (NT_STATUS_EQUAL(ntstatus,
					NT_STATUS_ILLEGAL_CHARACTER)) {
				/*
				 * Bad character conversion on name. Ignore this
				 * entry.
				 */
				continue;
			}
			if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
				out_of_space = true;
			} else {
				finished = !NT_STATUS_IS_OK(ntstatus);
			}
		}

		if (!finished && !out_of_space)
			numentries++;

		/*
		 * As an optimisation if we know we aren't looking
		 * for a wildcard name (ie. the name matches the wildcard exactly)
		 * then we can finish on any (first) match.
		 * This speeds up large directory searches. JRA.
		 */

		if(got_exact_match)
			finished = True;

		/* Ensure space_remaining never goes -ve. */
		if (PTR_DIFF(p,pdata) > max_data_bytes) {
			space_remaining = 0;
			out_of_space = true;
		} else {
			space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
		}
	}

	/* Check if we can close the dirptr */
	if(close_after_first || (finished && close_if_end)) {
		DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
		dptr_num = -1;
		close_file(NULL, fsp, NORMAL_CLOSE);
		fsp = NULL;
	}

	/*
	 * If there are no matching entries we must return ERRDOS/ERRbadfile -
	 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
	 * the protocol level is less than NT1. Tested with smbclient. JRA.
	 * This should fix the OS/2 client bug #2335.
	 */

	if(numentries == 0) {
		dptr_num = -1;
		/*
		 * We may have already closed the file in the
		 * close_after_first or finished case above.
		 */
		if (fsp != NULL) {
			close_file(NULL, fsp, NORMAL_CLOSE);
			fsp = NULL;
		}
		if (get_Protocol() < PROTOCOL_NT1) {
			reply_force_doserror(req, ERRDOS, ERRnofiles);
			goto out;
		} else {
			reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
					ERRDOS, ERRbadfile);
			goto out;
		}
	}

	/* At this point pdata points to numentries directory entries. */

	/* Set up the return parameter block */
	SSVAL(params,0,dptr_num);
	SSVAL(params,2,numentries);
	SSVAL(params,4,finished);
	SSVAL(params,6,0); /* Never an EA error */
	SSVAL(params,8,last_entry_off);

	send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
			    max_data_bytes);

	if ((! *directory) && dptr_path(sconn, dptr_num)) {
		directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
		if (!directory) {
			reply_nterror(req, NT_STATUS_NO_MEMORY);
		}
	}

	DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
		smb_fn_name(req->cmd),
		mask, directory, dirtype, numentries ) );

	/*
	 * Force a name mangle here to ensure that the
	 * mask as an 8.3 name is top of the mangled cache.
	 * The reasons for this are subtle. Don't remove
	 * this code unless you know what you are doing
	 * (see PR#13758). JRA.
	 */

	if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
		char mangled_name[13];
		name_to_8_3(mask, mangled_name, True, conn->params);
	}
 out:

	if (as_root) {
		unbecome_root();
	}

	TALLOC_FREE(smb_dname);
	return;
}

Project: samba
File: trans2.c

NTSTATUS refuse_symlink_fsp(const files_struct *fsp)
{

	if (!VALID_STAT(fsp->fsp_name->st)) {
		return NT_STATUS_ACCESS_DENIED;
	}
	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
		return NT_STATUS_ACCESS_DENIED;
	}
	if (fsp_get_pathref_fd(fsp) == -1) {
		return NT_STATUS_ACCESS_DENIED;
	}
	return NT_STATUS_OK;
}

Project: samba
File: trans2.c

static void call_trans2qfilepathinfo(connection_struct *conn,
				     struct smb_request *req,
				     unsigned int tran_call,
				     char **pparams, int total_params,
				     char **ppdata, int total_data,
				     unsigned int max_data_bytes)
{
	char *params = *pparams;
	char *pdata = *ppdata;
	uint16_t info_level;
	unsigned int data_size = 0;
	unsigned int param_size = 2;
	struct smb_filename *smb_fname = NULL;
	bool delete_pending = False;
	struct timespec write_time_ts;
	files_struct *fsp = NULL;
	struct file_id fileid;
	struct ea_list *ea_list = NULL;
	int lock_data_count = 0;
	char *lock_data = NULL;
	size_t fixed_portion;
	NTSTATUS status = NT_STATUS_OK;

	if (!params) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	ZERO_STRUCT(write_time_ts);

	if (tran_call == TRANSACT2_QFILEINFO) {
		if (total_params < 4) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			return;
		}

		if (IS_IPC(conn)) {
			call_trans2qpipeinfo(conn, req,	tran_call,
					     pparams, total_params,
					     ppdata, total_data,
					     max_data_bytes);
			return;
		}

		fsp = file_fsp(req, SVAL(params,0));
		info_level = SVAL(params,2);

		DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));

		if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
			reply_nterror(req, NT_STATUS_INVALID_LEVEL);
			return;
		}

		/* Initial check for valid fsp ptr. */
		if (!check_fsp_open(conn, req, fsp)) {
			return;
		}

		smb_fname = fsp->fsp_name;

		if(fsp->fake_file_handle) {
			/*
			 * This is actually for the QUOTA_FAKE_FILE --metze
			 */

			/* We know this name is ok, it's already passed the checks. */

		} else if(fsp_get_pathref_fd(fsp) == -1) {
			/*
			 * This is actually a QFILEINFO on a directory
			 * handle (returned from an NT SMB). NT5.0 seems
			 * to do this call. JRA.
			 */

			if (INFO_LEVEL_IS_UNIX(info_level)) {
				/* Always do lstat for UNIX calls. */
				if (SMB_VFS_LSTAT(conn, smb_fname)) {
					DEBUG(3,("call_trans2qfilepathinfo: "
						 "SMB_VFS_LSTAT of %s failed "
						 "(%s)\n",
						 smb_fname_str_dbg(smb_fname),
						 strerror(errno)));
					reply_nterror(req,
						map_nt_error_from_unix(errno));
					return;
				}
			} else if (SMB_VFS_STAT(conn, smb_fname)) {
				DEBUG(3,("call_trans2qfilepathinfo: "
					 "SMB_VFS_STAT of %s failed (%s)\n",
					 smb_fname_str_dbg(smb_fname),
					 strerror(errno)));
				reply_nterror(req,
					map_nt_error_from_unix(errno));
				return;
			}

			if (lp_smbd_getinfo_ask_sharemode(SNUM(conn))) {
				fileid = vfs_file_id_from_sbuf(
					conn, &smb_fname->st);
				get_file_infos(fileid, fsp->name_hash,
					       &delete_pending,
					       &write_time_ts);
			}
		} else {
			/*
			 * Original code - this is an open file.
			 */
			if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
				DEBUG(3, ("fstat of %s failed (%s)\n",
					  fsp_fnum_dbg(fsp), strerror(errno)));
				reply_nterror(req,
					map_nt_error_from_unix(errno));
				return;
			}
			if (lp_smbd_getinfo_ask_sharemode(SNUM(conn))) {
				fileid = vfs_file_id_from_sbuf(
					conn, &smb_fname->st);
				get_file_infos(fileid, fsp->name_hash,
					       &delete_pending,
					       &write_time_ts);
			}
		}

	} else {
		uint32_t name_hash;
		char *fname = NULL;
		uint32_t ucf_flags = ucf_flags_from_smb_request(req);

		/* qpathinfo */
		if (total_params < 7) {
			reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
			return;
		}

		info_level = SVAL(params,0);

		DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));

		if (INFO_LEVEL_IS_UNIX(info_level)) {
			if (!lp_unix_extensions()) {
				reply_nterror(req, NT_STATUS_INVALID_LEVEL);
				return;
			}
		}

		if (req->posix_pathnames) {
			srvstr_get_path_posix(req,
				params,
				req->flags2,
				&fname,
				&params[6],
				total_params - 6,
				STR_TERMINATE,
				&status);
		} else {
			srvstr_get_path(req,
				params,
				req->flags2,
				&fname,
				&params[6],
				total_params - 6,
				STR_TERMINATE,
				&status);
		}
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, status);
			return;
		}

		status = filename_convert(req,
					conn,
					fname,
					ucf_flags,
					0,
					&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,
						ERRSRV, ERRbadpath);
				return;
			}
			reply_nterror(req, status);
			return;
		}

		/*
		 * smb_fname->fsp may be NULL if smb_fname points at a symlink
		 * and we're in POSIX context, so be careful when using fsp
		 * below, it can still be NULL.
		 */
		fsp = smb_fname->fsp;

		/* If this is a stream, check if there is a delete_pending. */
		if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
		    && is_ntfs_stream_smb_fname(smb_fname)) {
			struct smb_filename *smb_fname_base;

			/* Create an smb_filename with stream_name == NULL. */
			smb_fname_base = synthetic_smb_fname(
						talloc_tos(),
						smb_fname->base_name,
						NULL,
						NULL,
						smb_fname->twrp,
						smb_fname->flags);
			if (smb_fname_base == NULL) {
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				return;
			}

			if (INFO_LEVEL_IS_UNIX(info_level) || req->posix_pathnames) {
				/* Always do lstat for UNIX calls. */
				if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
					DEBUG(3,("call_trans2qfilepathinfo: "
						 "SMB_VFS_LSTAT of %s failed "
						 "(%s)\n",
						 smb_fname_str_dbg(smb_fname_base),
						 strerror(errno)));
					TALLOC_FREE(smb_fname_base);
					reply_nterror(req,
						map_nt_error_from_unix(errno));
					return;
				}
			} else {
				if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
					DEBUG(3,("call_trans2qfilepathinfo: "
						 "fileinfo of %s failed "
						 "(%s)\n",
						 smb_fname_str_dbg(smb_fname_base),
						 strerror(errno)));
					TALLOC_FREE(smb_fname_base);
					reply_nterror(req,
						map_nt_error_from_unix(errno));
					return;
				}
			}

			status = file_name_hash(conn,
					smb_fname_str_dbg(smb_fname_base),
					&name_hash);
			if (!NT_STATUS_IS_OK(status)) {
				TALLOC_FREE(smb_fname_base);
				reply_nterror(req, status);
				return;
			}

			fileid = vfs_file_id_from_sbuf(conn,
						       &smb_fname_base->st);
			TALLOC_FREE(smb_fname_base);
			get_file_infos(fileid, name_hash, &delete_pending, NULL);
			if (delete_pending) {
				reply_nterror(req, NT_STATUS_DELETE_PENDING);
				return;
			}
		}

		if (INFO_LEVEL_IS_UNIX(info_level) || req->posix_pathnames) {
			/* Always do lstat for UNIX calls. */
			if (SMB_VFS_LSTAT(conn, smb_fname)) {
				DEBUG(3,("call_trans2qfilepathinfo: "
					 "SMB_VFS_LSTAT of %s failed (%s)\n",
					 smb_fname_str_dbg(smb_fname),
					 strerror(errno)));
				reply_nterror(req,
					map_nt_error_from_unix(errno));
				return;
			}

		} else {
			if (SMB_VFS_STAT(conn, smb_fname) != 0) {
				DEBUG(3,("call_trans2qfilepathinfo: "
					 "SMB_VFS_STAT of %s failed (%s)\n",
					 smb_fname_str_dbg(smb_fname),
					 strerror(errno)));
				reply_nterror(req,
					map_nt_error_from_unix(errno));
				return;
			}
		}

		status = file_name_hash(conn,
				smb_fname_str_dbg(smb_fname),
				&name_hash);
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, status);
			return;
		}

		if (lp_smbd_getinfo_ask_sharemode(SNUM(conn))) {
			fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
			get_file_infos(fileid, name_hash, &delete_pending,
				       &write_time_ts);
		}

		if (delete_pending) {
			reply_nterror(req, NT_STATUS_DELETE_PENDING);
			return;
		}
	}

	DEBUG(3,("call_trans2qfilepathinfo %s (%s) level=%d call=%d "
		 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
		 fsp_fnum_dbg(fsp),
		 info_level,tran_call,total_data));

	/* Pull out any data sent here before we realloc. */
	switch (info_level) {
		case SMB_INFO_QUERY_EAS_FROM_LIST:
		{
			/* Pull any EA list from the data portion. */
			uint32_t ea_size;

			if (total_data < 4) {
				reply_nterror(
					req, NT_STATUS_INVALID_PARAMETER);
				return;
			}
			ea_size = IVAL(pdata,0);

			if (total_data > 0 && ea_size != total_data) {
				DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
				reply_nterror(
					req, NT_STATUS_INVALID_PARAMETER);
				return;
			}

			if (!lp_ea_support(SNUM(conn))) {
				reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
				return;
			}

			/* Pull out the list of names. */
			ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
			if (!ea_list) {
				reply_nterror(
					req, NT_STATUS_INVALID_PARAMETER);
				return;
			}
			break;
		}

		case SMB_QUERY_POSIX_LOCK:
		{
			if (fsp == NULL ||
			    fsp->fsp_flags.is_pathref ||
			    fsp_get_io_fd(fsp) == -1)
			{
				reply_nterror(req, NT_STATUS_INVALID_HANDLE);
				return;
			}

			if (total_data != POSIX_LOCK_DATA_SIZE) {
				reply_nterror(
					req, NT_STATUS_INVALID_PARAMETER);
				return;
			}

			/* Copy the lock range data. */
			lock_data = (char *)talloc_memdup(
				req, pdata, total_data);
			if (!lock_data) {
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				return;
			}
			lock_data_count = total_data;
			break;
		}
		default:
			break;
	}

	*pparams = (char *)SMB_REALLOC(*pparams,2);
	if (*pparams == NULL) {
		reply_nterror(req, NT_STATUS_NO_MEMORY);
		return;
	}
	params = *pparams;
	SSVAL(params,0,0);

	/*
	 * draft-leach-cifs-v1-spec-02.txt
	 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
	 * says:
	 *
	 *  The requested information is placed in the Data portion of the
	 *  transaction response. For the information levels greater than 0x100,
	 *  the transaction response has 1 parameter word which should be
	 *  ignored by the client.
	 *
	 * However Windows only follows this rule for the IS_NAME_VALID call.
	 */
	switch (info_level) {
	case SMB_INFO_IS_NAME_VALID:
		param_size = 0;
		break;
	}

	if ((info_level & SMB2_INFO_SPECIAL) == SMB2_INFO_SPECIAL) {
		/*
		 * We use levels that start with 0xFF00
		 * internally to represent SMB2 specific levels
		 */
		reply_nterror(req, NT_STATUS_INVALID_LEVEL);
		return;
	}

	status = smbd_do_qfilepathinfo(conn, req, req, info_level,
				       fsp, smb_fname,
				       delete_pending, write_time_ts,
				       ea_list,
				       lock_data_count, lock_data,
				       req->flags2, max_data_bytes,
				       &fixed_portion,
				       ppdata, &data_size);
	if (!NT_STATUS_IS_OK(status)) {
		if (open_was_deferred(req->xconn, req->mid)) {
			/* We have re-scheduled this call. */
			return;
		}
		if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
			bool ok = defer_smb1_sharing_violation(req);
			if (ok) {
				return;
			}
		}
		reply_nterror(req, status);
		return;
	}
	if (fixed_portion > max_data_bytes) {
		reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
		return;
	}

	send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
			    max_data_bytes);

	return;
}

Project: samba
File: trans2.c

static void call_trans2getdfsreferral(connection_struct *conn,
				      struct smb_request *req,
				      char **pparams, int total_params,
				      char **ppdata, int total_data,
				      unsigned int max_data_bytes)
{
	char *params = *pparams;
  	char *pathname = NULL;
	int reply_size = 0;
	int max_referral_level;
	NTSTATUS status = NT_STATUS_OK;
	TALLOC_CTX *ctx = talloc_tos();

	DEBUG(10,("call_trans2getdfsreferral\n"));

	if (total_params < 3) {
		reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return;
	}

	max_referral_level = SVAL(params,0);

	if(!lp_host_msdfs()) {
		reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
		return;
	}

	srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
		    total_params - 2, STR_TERMINATE);
	if (!pathname) {
		reply_nterror(req, NT_STATUS_NOT_FOUND);
		return;
	}
	if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
					    ppdata,&status)) < 0) {
		reply_nterror(req, status);
		return;
	}

	SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
	      SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
	send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);

	return;
}

Project: samba
File: trans2.c

static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
					struct smb_request *req,
					const char *pdata,
					int total_data,
					files_struct *fsp,
					struct smb_filename *smb_fname)
{
	struct smb_file_time ft;
	uint32_t raw_unixmode;
	mode_t unixmode;
	off_t size = 0;
	uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
	gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
	NTSTATUS status = NT_STATUS_OK;
	enum perm_type ptype;
	files_struct *all_fsps = NULL;
	bool modify_mtime = true;
	struct file_id id;
	SMB_STRUCT_STAT sbuf;

	init_smb_file_time(&ft);

	if (total_data < 100) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
	   IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
		size=IVAL(pdata,0); /* first 8 Bytes are size */
		size |= (((off_t)IVAL(pdata,4)) << 32);
	}

	ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
	ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
	set_owner = (uid_t)IVAL(pdata,40);
	set_grp = (gid_t)IVAL(pdata,48);
	raw_unixmode = IVAL(pdata,84);

	if (VALID_STAT(smb_fname->st)) {
		if (S_ISDIR(smb_fname->st.st_ex_mode)) {
			ptype = PERM_EXISTING_DIR;
		} else {
			ptype = PERM_EXISTING_FILE;
		}
	} else {
		ptype = PERM_NEW_FILE;
	}

	status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
				      ptype, &unixmode);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
		  "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
		  smb_fname_str_dbg(smb_fname), (double)size,
		  (unsigned int)set_owner, (unsigned int)set_grp,
		  (int)raw_unixmode));

	sbuf = smb_fname->st;

	if (!VALID_STAT(sbuf)) {
		/*
		 * The only valid use of this is to create character and block
		 * devices, and named pipes. This is deprecated (IMHO) and 
		 * a new info level should be used for mknod. JRA.
		 */

		return smb_unix_mknod(conn,
					pdata,
					total_data,
					smb_fname);
	}

#if 1
	/* Horrible backwards compatibility hack as an old server bug
	 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
	 * */

	if (!size) {
		size = get_file_size_stat(&sbuf);
	}
#endif

	/*
	 * Deal with the UNIX specific mode set.
	 */

	if (raw_unixmode != SMB_MODE_NO_CHANGE) {
		int ret;

		if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
			DBG_WARNING("Can't set mode on symlink %s\n",
				smb_fname_str_dbg(smb_fname));
			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
		}

		DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
			  "setting mode 0%o for file %s\n",
			  (unsigned int)unixmode,
			  smb_fname_str_dbg(smb_fname)));
		ret = SMB_VFS_FCHMOD(fsp, unixmode);
		if (ret != 0) {
			return map_nt_error_from_unix(errno);
		}
	}

	/*
	 * Deal with the UNIX specific uid set.
	 */

	if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
	    (sbuf.st_ex_uid != set_owner)) {
		int ret;

		DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
			  "changing owner %u for path %s\n",
			  (unsigned int)set_owner,
			  smb_fname_str_dbg(smb_fname)));

		if (fsp &&
		    !fsp->fsp_flags.is_pathref &&
		    fsp_get_io_fd(fsp) != -1)
		{
			ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
		} else {
			/*
			 * UNIX extensions calls must always operate
			 * on symlinks.
			 */
			ret = SMB_VFS_LCHOWN(conn, smb_fname,
					     set_owner, (gid_t)-1);
		}

		if (ret != 0) {
			status = map_nt_error_from_unix(errno);
			return status;
		}
	}

	/*
	 * Deal with the UNIX specific gid set.
	 */

	if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
	    (sbuf.st_ex_gid != set_grp)) {
		int ret;

		DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
			  "changing group %u for file %s\n",
			  (unsigned int)set_grp,
			  smb_fname_str_dbg(smb_fname)));
		if (fsp &&
		    !fsp->fsp_flags.is_pathref &&
		    fsp_get_io_fd(fsp) != -1)
		{
			ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
		} else {
			/*
			 * UNIX extensions calls must always operate
			 * on symlinks.
			 */
			ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
				  set_grp);
		}
		if (ret != 0) {
			status = map_nt_error_from_unix(errno);
			return status;
		}
	}

	/* Deal with any size changes. */

	if (S_ISREG(sbuf.st_ex_mode)) {
		status = smb_set_file_size(conn, req,
					   fsp,
					   smb_fname,
					   &sbuf,
					   size,
					   false);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
	}

	/* Deal with any time changes. */
	if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
		/* No change, don't cancel anything. */
		return status;
	}

	id = vfs_file_id_from_sbuf(conn, &sbuf);
	for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
			all_fsps = file_find_di_next(all_fsps, true)) {
		/*
		 * We're setting the time explicitly for UNIX.
		 * Cancel any pending changes over all handles.
		 */
		all_fsps->fsp_flags.update_write_time_on_close = false;
		TALLOC_FREE(all_fsps->update_write_time_event);
	}

	/*
	 * Override the "setting_write_time"
	 * parameter here as it almost does what
	 * we need. Just remember if we modified
	 * mtime and send the notify ourselves.
	 */
	if (is_omit_timespec(&ft.mtime)) {
		modify_mtime = false;
	}

	status = smb_set_file_time(conn,
				fsp,
				smb_fname,
				&ft,
				false);
	if (modify_mtime) {
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
	}
	return status;
}