[ea] pass ea to daemonon open

if an EA buffer is given on create, map it to use space and pass
it to the daemon

removed check for FILE_WRITE_EA permission; it isn't required on ntfs

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Olga Kornievskaia 2012-05-03 10:56:47 -04:00
parent 380e04867d
commit 470d0832ee
3 changed files with 84 additions and 12 deletions

View file

@ -275,13 +275,15 @@ static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upca
if (status) goto out;
status = safe_read(&buffer, &length, &args->srv_open, sizeof(HANDLE));
if (status) goto out;
status = safe_read(&buffer, &length, &args->ea, sizeof(HANDLE));
if (status) goto out;
dprintf(1, "parsing NFS41_OPEN: filename='%s' access mask=%d "
"access mode=%d\n\tfile attrs=0x%x create attrs=0x%x "
"(kernel) disposition=%d\n\topen_owner_id=%d mode=%o "
"srv_open=%x\n", args->path, args->access_mask, args->access_mode,
"srv_open=%p ea=%p\n", args->path, args->access_mask, args->access_mode,
args->file_attrs, args->create_opts, args->disposition,
args->open_owner_id, args->mode, args->srv_open);
args->open_owner_id, args->mode, args->srv_open, args->ea);
print_disposition(2, args->disposition);
print_access_mask(2, args->access_mask);
print_share_mode(2, args->access_mode);

View file

@ -53,6 +53,7 @@ typedef struct __open_upcall_args {
ULONGLONG changeattr;
HANDLE srv_open;
DWORD deleg_type;
PFILE_FULL_EA_INFORMATION ea;
BOOLEAN created;
BOOLEAN symlink_embedded;
} open_upcall_args;

View file

@ -205,6 +205,8 @@ typedef struct _updowncall_entry {
HANDLE srv_open;
DWORD deleg_type;
BOOLEAN symlink_embedded;
PMDL EaMdl;
PVOID EaBuffer;
} Open;
struct {
PUNICODE_STRING filename;
@ -680,7 +682,7 @@ NTSTATUS marshal_nfs41_open(
else
tmp += *len;
header_len = *len + length_as_utf8(entry->u.Open.filename) +
5 * sizeof(ULONG) + sizeof(LONG) + sizeof(DWORD) + sizeof(HANDLE);
5 * sizeof(ULONG) + sizeof(LONG) + sizeof(DWORD) + 2 * sizeof(HANDLE);
if (header_len > buf_len) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto out;
@ -705,16 +707,35 @@ NTSTATUS marshal_nfs41_open(
RtlCopyMemory(tmp, &entry->u.Open.mode, sizeof(DWORD));
tmp += sizeof(DWORD);
RtlCopyMemory(tmp, &entry->u.Open.srv_open, sizeof(HANDLE));
tmp += sizeof(HANDLE);
__try {
if (entry->u.Open.EaMdl) {
entry->u.Open.EaBuffer =
MmMapLockedPagesSpecifyCache(entry->u.Open.EaMdl,
UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
if (entry->u.Open.EaBuffer == NULL) {
print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto out;
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
print_error("Call to MmMapLocked failed due to exception 0x%x\n", GetExceptionCode());
status = STATUS_ACCESS_DENIED;
goto out;
}
RtlCopyMemory(tmp, &entry->u.Open.EaBuffer, sizeof(HANDLE));
*len = header_len;
#ifdef DEBUG_MARSHAL_DETAIL
DbgP("marshal_nfs41_open: name=%wZ mask=0x%x access=0x%x attrs=0x%x "
"opts=0x%x dispo=0x%x open_owner_id=0x%x mode=%o srv_open=%p\n",
"opts=0x%x dispo=0x%x open_owner_id=0x%x mode=%o srv_open=%p ea=%p\n",
entry->u.Open.filename, entry->u.Open.access_mask,
entry->u.Open.access_mode, entry->u.Open.attrs, entry->u.Open.copts,
entry->u.Open.disp, entry->u.Open.open_owner_id, entry->u.Open.mode,
entry->u.Open.srv_open);
entry->u.Open.srv_open, entry->u.Open.EaBuffer);
#endif
out:
return status;
@ -1650,6 +1671,15 @@ NTSTATUS unmarshal_nfs41_open(
{
NTSTATUS status = STATUS_SUCCESS;
__try {
if (cur->u.Open.EaBuffer)
MmUnmapLockedPages(cur->u.Open.EaBuffer, cur->u.Open.EaMdl);
} __except(EXCEPTION_EXECUTE_HANDLER) {
print_error("MmUnmapLockedPages thrown exception=0x%0x\n", GetExceptionCode());
status = cur->status = STATUS_ACCESS_DENIED;
goto out;
}
RtlCopyMemory(&cur->u.Open.binfo, *buf, sizeof(FILE_BASIC_INFORMATION));
*buf += sizeof(FILE_BASIC_INFORMATION);
RtlCopyMemory(&cur->u.Open.sinfo, *buf, sizeof(FILE_STANDARD_INFORMATION));
@ -1846,6 +1876,14 @@ NTSTATUS nfs41_downcall(
MmUnmapLockedPages(cur->u.QueryFile.mdl_buf,
cur->u.QueryFile.mdl);
IoFreeMdl(cur->u.QueryFile.mdl);
break;
case NFS41_OPEN:
if (cur->u.Open.EaMdl) {
MmUnmapLockedPages(cur->u.Open.EaBuffer,
cur->u.Open.EaMdl);
IoFreeMdl(cur->u.Open.EaMdl);
}
break;
}
ExReleaseFastMutex(&cur->lock);
nfs41_RemoveEntry(downcallLock, downcall, cur);
@ -3407,6 +3445,21 @@ DWORD map_disposition_to_create_retval(
}
}
static BOOLEAN create_should_pass_ea(
IN PFILE_FULL_EA_INFORMATION ea,
IN ULONG disposition)
{
/* don't pass cygwin EAs (until we support NfsSymlinkTargetName) */
if (AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength)
|| AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength)
|| AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength))
return FALSE;
/* only set EAs on file creation */
return disposition == FILE_SUPERSEDE || disposition == FILE_CREATE
|| disposition == FILE_OPEN_IF || disposition == FILE_OVERWRITE
|| disposition == FILE_OVERWRITE_IF;
}
NTSTATUS check_nfs41_create_args(
IN PRX_CONTEXT RxContext)
{
@ -3512,10 +3565,6 @@ NTSTATUS check_nfs41_create_args(
status = STATUS_EAS_NOT_SUPPORTED;
goto out;
}
if ((params->DesiredAccess & FILE_WRITE_EA) == 0) {
status = STATUS_ACCESS_DENIED;
goto out;
}
}
} else if (RxContext->CurrentIrpSp->Parameters.Create.EaLength) {
status = STATUS_INVALID_PARAMETER;
@ -3599,12 +3648,32 @@ NTSTATUS nfs41_Create(
if (params->FileAttributes & FILE_ATTRIBUTE_READONLY)
entry->u.Open.mode = 0444;
}
if (ea && create_should_pass_ea(ea, params->Disposition)) {
/* lock the extended attribute buffer for read access in user space */
entry->u.Open.EaMdl = IoAllocateMdl(ea,
RxContext->CurrentIrpSp->Parameters.Create.EaLength,
FALSE, FALSE, NULL);
if (entry->u.Open.EaMdl == NULL) {
status = STATUS_INTERNAL_ERROR;
RxFreePool(entry);
goto out;
}
entry->u.Open.EaMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
MmProbeAndLockPages(entry->u.Open.EaMdl, KernelMode, IoModifyAccess);
}
status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
#ifndef USE_MOUNT_SEC_CONTEXT
SeDeleteClientSecurity(&entry->sec_ctx);
#endif
if (status) goto out;
if (entry->u.Open.EaMdl) {
MmUnlockPages(entry->u.Open.EaMdl);
IoFreeMdl(entry->u.Open.EaMdl);
}
if (entry->status == NO_ERROR && entry->errno == ERROR_REPARSE) {
/* symbolic link handling. when attempting to open a symlink when the
* FILE_OPEN_REPARSE_POINT flag is not set, replace the filename with