ReactOS  0.4.10-dev-234-g15c29d0
nfs41_driver.c
Go to the documentation of this file.
1 /* NFSv4.1 client for Windows
2  * Copyright © 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose. See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #define MINIRDR__NAME "Value is ignored, only fact of definition"
23 #include <rx.h>
24 #include <windef.h>
25 #include <winerror.h>
26 
27 #include <ntstrsafe.h>
28 
29 #ifdef __REACTOS__
30 #include <pseh/pseh2.h>
31 #endif
32 
33 #include "nfs41_driver.h"
34 #include "nfs41_np.h"
35 #include "nfs41_debug.h"
36 
37 #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7)
38 NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
39  ULONG *utf8_bytes_written,
40  const WCHAR *uni_src, ULONG uni_bytes);
41 NTSTATUS NTAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max,
42  ULONG *uni_bytes_written,
43  const CHAR *utf8_src, ULONG utf8_bytes);
44 #endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
45 
46 #define USE_MOUNT_SEC_CONTEXT
47 
48 /* debugging printout defines */
49 //#define DEBUG_FSDDISPATCH
50 #define DEBUG_MARSHAL_HEADER
51 #define DEBUG_MARSHAL_DETAIL
52 //#define DEBUG_OPEN
53 //#define DEBUG_CLOSE
54 //#define DEBUG_CACHE
55 #define DEBUG_INVALIDATE_CACHE
56 //#define DEBUG_READ
57 //#define DEBUG_WRITE
58 //#define DEBUG_DIR_QUERY
59 //#define DEBUG_FILE_QUERY
60 //#define DEBUG_FILE_SET
61 //#define DEBUG_ACL_QUERY
62 //#define DEBUG_ACL_SET
63 //#define DEBUG_EA_QUERY
64 //#define DEBUG_EA_SET
65 //#define DEBUG_LOCK
66 //#define DEBUG_MISC
67 #define DEBUG_TIME_BASED_COHERENCY
68 #define DEBUG_MOUNT
69 //#define DEBUG_VOLUME_QUERY
70 
71 //#define ENABLE_TIMINGS
72 //#define ENABLE_INDV_TIMINGS
73 #ifdef ENABLE_TIMINGS
74 typedef struct __nfs41_timings {
75  LONG tops, sops;
76  LONGLONG ticks, size;
77 } nfs41_timings;
78 
79 nfs41_timings lookup, readdir, open, close, getattr, setattr, getacl, setacl, volume,
80  read, write, lock, unlock, setexattr, getexattr;
81 #endif
82 DRIVER_INITIALIZE DriverEntry;
83 DRIVER_UNLOAD nfs41_driver_unload;
85 
88 
89 #define DISABLE_CACHING 0
90 #define ENABLE_READ_CACHING 1
91 #define ENABLE_WRITE_CACHING 2
92 #define ENABLE_READWRITE_CACHING 3
93 
94 #define NFS41_MM_POOLTAG ('nfs4')
95 #define NFS41_MM_POOLTAG_ACL ('acls')
96 #define NFS41_MM_POOLTAG_MOUNT ('mnts')
97 #define NFS41_MM_POOLTAG_OPEN ('open')
98 #define NFS41_MM_POOLTAG_UP ('upca')
99 #define NFS41_MM_POOLTAG_DOWN ('down')
100 
105 
108 
109 #define DECLARE_CONST_ANSI_STRING(_var, _string) \
110  const CHAR _var ## _buffer[] = _string; \
111  const ANSI_STRING _var = { sizeof(_string) - sizeof(CHAR), \
112  sizeof(_string), (PCH) _var ## _buffer }
113 #define RELATIVE(wait) (-(wait))
114 #define NANOSECONDS(nanos) (((signed __int64)(nanos)) / 100L)
115 #define MICROSECONDS(micros) (((signed __int64)(micros)) * NANOSECONDS(1000L))
116 #define MILLISECONDS(milli) (((signed __int64)(milli)) * MICROSECONDS(1000L))
117 #define SECONDS(seconds) (((signed __int64)(seconds)) * MILLISECONDS(1000L))
118 
119 DECLARE_CONST_ANSI_STRING(NfsV3Attributes, "NfsV3Attributes");
120 DECLARE_CONST_ANSI_STRING(NfsSymlinkTargetName, "NfsSymlinkTargetName");
121 DECLARE_CONST_ANSI_STRING(NfsActOnLink, "NfsActOnLink");
122 
124  IN const ANSI_STRING *lhs,
125  IN const CHAR *rhs,
126  IN const UCHAR rhs_len)
127 {
128  return lhs->Length == rhs_len &&
129  RtlCompareMemory(lhs->Buffer, rhs, rhs_len) == rhs_len;
130 }
131 
132 typedef struct _nfs3_attrs {
135  struct {
138  } rdev;
141 } nfs3_attrs;
142 LARGE_INTEGER unix_time_diff; //needed to convert windows time to unix
143 
144 enum ftype3 {
145  NF3REG = 1,
152 };
153 
160 
161 #ifdef __REACTOS__
162 #undef _errno
163 #undef errno
164 #endif
165 
166 typedef struct _updowncall_entry {
185  union {
186  struct {
194  } Mount;
195  struct {
199  } ReadWrite;
200  struct {
205  } Lock;
206  struct {
209  } Unlock;
210  struct {
227  } Open;
228  struct {
230  BOOLEAN remove;
232  } Close;
233  struct {
241  } QueryFile;
242  struct {
244  } SetFile;
245  struct {
246  DWORD mode;
247  } SetEa;
248  struct {
255  } QueryEa;
256  struct {
259  } Symlink;
260  struct {
262  } Volume;
263  struct {
265  } Acl;
266  } u;
267 
269 
270 typedef struct _updowncall_list {
274 
275 typedef struct _nfs41_mount_entry {
283 
284 typedef struct _nfs41_mount_list {
287 
288 #define nfs41_AddEntry(lock,list,pEntry) \
289  ExAcquireFastMutex(&lock); \
290  InsertTailList(&(list).head, &(pEntry)->next); \
291  ExReleaseFastMutex(&lock);
292 #define nfs41_RemoveFirst(lock,list,pEntry) \
293  ExAcquireFastMutex(&lock); \
294  pEntry = (IsListEmpty(&(list).head) \
295  ? NULL \
296  : RemoveHeadList(&(list).head)); \
297  ExReleaseFastMutex(&lock);
298 #define nfs41_RemoveEntry(lock,pEntry) \
299  ExAcquireFastMutex(&lock); \
300  RemoveEntryList(&pEntry->next); \
301  ExReleaseFastMutex(&lock);
302 #define nfs41_IsListEmpty(lock,list,flag) \
303  ExAcquireFastMutex(&lock); \
304  flag = IsListEmpty(&(list).head); \
305  ExReleaseFastMutex(&lock);
306 #define nfs41_GetFirstEntry(lock,list,pEntry) \
307  ExAcquireFastMutex(&lock); \
308  pEntry = (IsListEmpty(&(list).head) \
309  ? NULL \
310  : (nfs41_updowncall_entry *) \
311  (CONTAINING_RECORD((list).head.Flink, \
312  nfs41_updowncall_entry, \
313  next))); \
314  ExReleaseFastMutex(&lock);
315 #define nfs41_GetFirstMountEntry(lock,list,pEntry) \
316  ExAcquireFastMutex(&lock); \
317  pEntry = (IsListEmpty(&(list).head) \
318  ? NULL \
319  : (nfs41_mount_entry *) \
320  (CONTAINING_RECORD((list).head.Flink, \
321  nfs41_mount_entry, \
322  next))); \
323  ExReleaseFastMutex(&lock);
324 
325 /* In order to cooperate with other network providers,
326  * we only claim paths of the format '\\server\nfs4\path' */
327 DECLARE_CONST_UNICODE_STRING(NfsPrefix, L"\\nfs4");
328 DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME, L"sys");
329 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME, L"krb5");
330 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME, L"krb5i");
331 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME, L"krb5p");
333 DECLARE_CONST_UNICODE_STRING(EMPTY_STRING, L"");
334 
335 #define SERVER_NAME_BUFFER_SIZE 1024
336 #define MOUNT_CONFIG_RW_SIZE_MIN 1024
337 #define MOUNT_CONFIG_RW_SIZE_DEFAULT 1048576
338 #define MOUNT_CONFIG_RW_SIZE_MAX 1048576
339 #define MAX_SEC_FLAVOR_LEN 12
340 #define UPCALL_TIMEOUT_DEFAULT 50 /* in seconds */
341 
342 typedef struct _NFS41_MOUNT_CONFIG {
356 
357 typedef struct _NFS41_NETROOT_EXTENSION {
365 #define NFS41GetNetRootExtension(pNetRoot) \
366  (((pNetRoot) == NULL) ? NULL : \
367  (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context))
368 
369 /* FileSystemName as reported by FileFsAttributeInfo query */
370 #define FS_NAME L"NFS"
371 #define FS_NAME_LEN (sizeof(FS_NAME) - sizeof(WCHAR))
372 #define FS_ATTR_LEN (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + FS_NAME_LEN)
373 
374 /* FileSystemName as reported by FileFsAttributeInfo query */
375 #define VOL_NAME L"PnfsVolume"
376 #define VOL_NAME_LEN (sizeof(VOL_NAME) - sizeof(WCHAR))
377 #define VOL_ATTR_LEN (sizeof(FILE_FS_VOLUME_INFORMATION) + VOL_NAME_LEN)
378 
390 #define STORE_MOUNT_SEC_CONTEXT
391 #ifdef STORE_MOUNT_SEC_CONTEXT
393 #endif
395 #define NFS41GetVNetRootExtension(pVNetRoot) \
396  (((pVNetRoot) == NULL) ? NULL : \
397  (PNFS41_V_NET_ROOT_EXTENSION)((pVNetRoot)->Context))
398 
399 typedef struct _NFS41_FCB {
409 #define NFS41GetFcbExtension(pFcb) \
410  (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context))
411 
412 typedef struct _NFS41_FOBX {
415 
425 #define NFS41GetFobxExtension(pFobx) \
426  (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
427 
428 typedef struct _NFS41_SERVER_ENTRY {
431  UNICODE_STRING Name; // the server name.
433 
434 typedef struct _NFS41_DEVICE_EXTENSION {
445 
446 #define NFS41GetDeviceExtension(RxContext,pExt) \
447  PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \
448  ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
449 
450 typedef struct _nfs41_fcb_list_entry {
454  PNFS41_FOBX nfs41_fobx;
458 
459 typedef struct _nfs41_fcb_list {
463 
467 #define RxDefineNode( node, type ) \
468  node->NodeTypeCode = NTC_##type; \
469  node->NodeByteSize = sizeof(type);
470 
471 #define RDR_NULL_STATE 0
472 #define RDR_UNLOADED 1
473 #define RDR_UNLOADING 2
474 #define RDR_LOADING 3
475 #define RDR_LOADED 4
476 #define RDR_STOPPED 5
477 #define RDR_STOPPING 6
478 #define RDR_STARTING 7
479 #define RDR_STARTED 8
480 
483 
485 
487  PRX_CONTEXT RxContext)
488 {
489 
491 
492  if (IrpSp) {
493  DbgP("FileOject %p name %wZ access r=%d,w=%d,d=%d share r=%d,w=%d,d=%d\n",
494  IrpSp->FileObject, &IrpSp->FileObject->FileName,
495  IrpSp->FileObject->ReadAccess, IrpSp->FileObject->WriteAccess,
496  IrpSp->FileObject->DeleteAccess, IrpSp->FileObject->SharedRead,
497  IrpSp->FileObject->SharedWrite, IrpSp->FileObject->SharedDelete);
498  print_file_object(0, IrpSp->FileObject);
499  print_irps_flags(0, RxContext->CurrentIrpSp);
500  } else
501  DbgP("Couldn't print FileObject IrpSp is NULL\n");
502 
503  print_fo_all(1, RxContext);
504  if (RxContext->CurrentIrp)
505  print_irp_flags(0, RxContext->CurrentIrp);
506 }
507 
508 /* convert strings from unicode -> ansi during marshalling to
509  * save space in the upcall buffers and avoid extra copies */
512 {
513  ULONG ActualCount = 0;
514  RtlUnicodeToUTF8N(NULL, 0xffff, &ActualCount, str->Buffer, str->Length);
515  return sizeof(str->MaximumLength) + ActualCount + sizeof(UNICODE_NULL);
516 }
517 
519  IN OUT unsigned char **pos,
521 {
522  ANSI_STRING ansi;
523  ULONG ActualCount;
525 
526  if (str->Length == 0) {
527  status = STATUS_SUCCESS;
528  ActualCount = 0;
529  ansi.MaximumLength = 1;
530  goto out_copy;
531  }
532 
533  /* query the number of bytes required for the utf8 encoding */
534  status = RtlUnicodeToUTF8N(NULL, 0xffff,
535  &ActualCount, str->Buffer, str->Length);
536  if (status) {
537  print_error("RtlUnicodeToUTF8N('%wZ') failed with 0x%08X\n",
538  str, status);
539  goto out;
540  }
541 
542  /* convert the string directly into the upcall buffer */
543  ansi.Buffer = (PCHAR)*pos + sizeof(ansi.MaximumLength);
544  ansi.MaximumLength = (USHORT)ActualCount + sizeof(UNICODE_NULL);
545  status = RtlUnicodeToUTF8N(ansi.Buffer, ansi.MaximumLength,
546  &ActualCount, str->Buffer, str->Length);
547  if (status) {
548  print_error("RtlUnicodeToUTF8N(%hu, '%wZ', %hu) failed with 0x%08X\n",
549  ansi.MaximumLength, str, str->Length, status);
550  goto out;
551  }
552 
553 out_copy:
554  RtlCopyMemory(*pos, &ansi.MaximumLength, sizeof(ansi.MaximumLength));
555  *pos += sizeof(ansi.MaximumLength);
556  (*pos)[ActualCount] = '\0';
557  *pos += ansi.MaximumLength;
558 out:
559  return status;
560 }
561 
564  unsigned char *buf,
565  ULONG buf_len,
566  ULONG *len)
567 {
569  ULONG header_len = 0;
570  unsigned char *tmp = buf;
571 
572  header_len = sizeof(entry->version) + sizeof(entry->xid) +
573  sizeof(entry->opcode) + 2 * sizeof(HANDLE);
574  if (header_len > buf_len) {
576  goto out;
577  }
578  else
579  *len = header_len;
580  RtlCopyMemory(tmp, &entry->version, sizeof(entry->version));
581  tmp += sizeof(entry->version);
582  RtlCopyMemory(tmp, &entry->xid, sizeof(entry->xid));
583  tmp += sizeof(entry->xid);
584  RtlCopyMemory(tmp, &entry->opcode, sizeof(entry->opcode));
585  tmp += sizeof(entry->opcode);
586  RtlCopyMemory(tmp, &entry->session, sizeof(HANDLE));
587  tmp += sizeof(HANDLE);
588  RtlCopyMemory(tmp, &entry->open_state, sizeof(HANDLE));
589  tmp += sizeof(HANDLE);
590 
591 #ifdef DEBUG_MARSHAL_HEADER
592  if (MmIsAddressValid(entry->filename))
593  DbgP("[upcall header] xid=%lld opcode=%s filename=%wZ version=%d "
594  "session=0x%x open_state=0x%x\n", entry->xid,
595  opcode2string(entry->opcode), entry->filename,
596  entry->version, entry->session, entry->open_state);
597  else
598  status = STATUS_INTERNAL_ERROR;
599 #endif
600 out:
601  return status;
602 }
603 
604 const char* secflavorop2name(
606 {
607  switch(sec_flavor) {
608  case RPCSEC_AUTH_SYS: return "AUTH_SYS";
609  case RPCSEC_AUTHGSS_KRB5: return "AUTHGSS_KRB5";
610  case RPCSEC_AUTHGSS_KRB5I: return "AUTHGSS_KRB5I";
611  case RPCSEC_AUTHGSS_KRB5P: return "AUTHGSS_KRB5P";
612  }
613 
614  return "UNKNOWN FLAVOR";
615 }
618  unsigned char *buf,
619  ULONG buf_len,
620  ULONG *len)
621 {
623  ULONG header_len = 0;
624  unsigned char *tmp = buf;
625 
626  status = marshal_nfs41_header(entry, tmp, buf_len, len);
627  if (status) goto out;
628  else tmp += *len;
629 
630  /* 03/25/2011: Kernel crash to nfsd not running but mount upcall cued up */
631  if (!MmIsAddressValid(entry->u.Mount.srv_name) ||
632  !MmIsAddressValid(entry->u.Mount.root)) {
633  status = STATUS_INTERNAL_ERROR;
634  goto out;
635  }
636  header_len = *len + length_as_utf8(entry->u.Mount.srv_name) +
637  length_as_utf8(entry->u.Mount.root) + 3 * sizeof(DWORD);
638  if (header_len > buf_len) {
640  goto out;
641  }
642  status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.srv_name);
643  if (status) goto out;
644  status = marshall_unicode_as_utf8(&tmp, entry->u.Mount.root);
645  if (status) goto out;
646  RtlCopyMemory(tmp, &entry->u.Mount.sec_flavor, sizeof(DWORD));
647  tmp += sizeof(DWORD);
648  RtlCopyMemory(tmp, &entry->u.Mount.rsize, sizeof(DWORD));
649  tmp += sizeof(DWORD);
650  RtlCopyMemory(tmp, &entry->u.Mount.wsize, sizeof(DWORD));
651 
652  *len = header_len;
653 
654 #ifdef DEBUG_MARSHAL_DETAIL
655  DbgP("marshal_nfs41_mount: server name=%wZ mount point=%wZ sec_flavor=%s "
656  "rsize=%d wsize=%d\n", entry->u.Mount.srv_name, entry->u.Mount.root,
657  secflavorop2name(entry->u.Mount.sec_flavor), entry->u.Mount.rsize,
658  entry->u.Mount.wsize);
659 #endif
660 out:
661  return status;
662 }
663 
666  unsigned char *buf,
667  ULONG buf_len,
668  ULONG *len)
669 {
670  return marshal_nfs41_header(entry, buf, buf_len, len);
671 }
672 
675  unsigned char *buf,
676  ULONG buf_len,
677  ULONG *len)
678 {
680  ULONG header_len = 0;
681  unsigned char *tmp = buf;
682 
683  status = marshal_nfs41_header(entry, tmp, buf_len, len);
684  if (status) goto out;
685  else tmp += *len;
686 
687  header_len = *len + length_as_utf8(entry->filename) +
688  7 * sizeof(ULONG) + 2 * sizeof(HANDLE) +
689  length_as_utf8(&entry->u.Open.symlink);
690  if (header_len > buf_len) {
692  goto out;
693  }
694  status = marshall_unicode_as_utf8(&tmp, entry->filename);
695  if (status) goto out;
696  RtlCopyMemory(tmp, &entry->u.Open.access_mask,
697  sizeof(entry->u.Open.access_mask));
698  tmp += sizeof(entry->u.Open.access_mask);
699  RtlCopyMemory(tmp, &entry->u.Open.access_mode,
700  sizeof(entry->u.Open.access_mode));
701  tmp += sizeof(entry->u.Open.access_mode);
702  RtlCopyMemory(tmp, &entry->u.Open.attrs, sizeof(entry->u.Open.attrs));
703  tmp += sizeof(entry->u.Open.attrs);
704  RtlCopyMemory(tmp, &entry->u.Open.copts, sizeof(entry->u.Open.copts));
705  tmp += sizeof(entry->u.Open.copts);
706  RtlCopyMemory(tmp, &entry->u.Open.disp, sizeof(entry->u.Open.disp));
707  tmp += sizeof(entry->u.Open.disp);
708  RtlCopyMemory(tmp, &entry->u.Open.open_owner_id,
709  sizeof(entry->u.Open.open_owner_id));
710  tmp += sizeof(entry->u.Open.open_owner_id);
711  RtlCopyMemory(tmp, &entry->u.Open.mode, sizeof(DWORD));
712  tmp += sizeof(DWORD);
713  RtlCopyMemory(tmp, &entry->u.Open.srv_open, sizeof(HANDLE));
714  tmp += sizeof(HANDLE);
715  status = marshall_unicode_as_utf8(&tmp, &entry->u.Open.symlink);
716  if (status) goto out;
717 
718  _SEH2_TRY {
719  if (entry->u.Open.EaMdl) {
720  entry->u.Open.EaBuffer =
721  MmMapLockedPagesSpecifyCache(entry->u.Open.EaMdl,
722 #ifndef __REACTOS__
724 #else
726 #endif
727  if (entry->u.Open.EaBuffer == NULL) {
728  print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
730  goto out;
731  }
732  }
734  print_error("Call to MmMapLocked failed due to exception 0x%x\n", _SEH2_GetExceptionCode());
735  status = STATUS_ACCESS_DENIED;
736  goto out;
737  } _SEH2_END;
738  RtlCopyMemory(tmp, &entry->u.Open.EaBuffer, sizeof(HANDLE));
739  *len = header_len;
740 
741 #ifdef DEBUG_MARSHAL_DETAIL
742  DbgP("marshal_nfs41_open: name=%wZ mask=0x%x access=0x%x attrs=0x%x "
743  "opts=0x%x dispo=0x%x open_owner_id=0x%x mode=%o srv_open=%p ea=%p\n",
744  entry->filename, entry->u.Open.access_mask,
745  entry->u.Open.access_mode, entry->u.Open.attrs, entry->u.Open.copts,
746  entry->u.Open.disp, entry->u.Open.open_owner_id, entry->u.Open.mode,
747  entry->u.Open.srv_open, entry->u.Open.EaBuffer);
748 #endif
749 out:
750  return status;
751 }
752 
755  unsigned char *buf,
756  ULONG buf_len,
757  ULONG *len)
758 {
760  ULONG header_len = 0;
761  unsigned char *tmp = buf;
762 
763  status = marshal_nfs41_header(entry, tmp, buf_len, len);
764  if (status) goto out;
765  else tmp += *len;
766 
767  header_len = *len + sizeof(entry->buf_len) +
768  sizeof(entry->u.ReadWrite.offset) + sizeof(HANDLE);
769  if (header_len > buf_len) {
771  goto out;
772  }
773 
774  RtlCopyMemory(tmp, &entry->buf_len, sizeof(entry->buf_len));
775  tmp += sizeof(entry->buf_len);
776  RtlCopyMemory(tmp, &entry->u.ReadWrite.offset,
777  sizeof(entry->u.ReadWrite.offset));
778  tmp += sizeof(entry->u.ReadWrite.offset);
779  _SEH2_TRY {
780  entry->u.ReadWrite.MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
781  entry->buf =
782  MmMapLockedPagesSpecifyCache(entry->u.ReadWrite.MdlAddress,
783 #ifndef __REACTOS__
785 #else
787 #endif
788  if (entry->buf == NULL) {
789  print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
791  goto out;
792  }
794  NTSTATUS code;
795  code = _SEH2_GetExceptionCode();
796  print_error("Call to MmMapLocked failed due to exception 0x%x\n", code);
797  status = STATUS_ACCESS_DENIED;
798  goto out;
799  } _SEH2_END;
800  RtlCopyMemory(tmp, &entry->buf, sizeof(HANDLE));
801  *len = header_len;
802 
803 #ifdef DEBUG_MARSHAL_DETAIL
804  DbgP("marshal_nfs41_rw: len=%lu offset=%llu MdlAddress=%p Userspace=%p\n",
805  entry->buf_len, entry->u.ReadWrite.offset,
806  entry->u.ReadWrite.MdlAddress, entry->buf);
807 #endif
808 out:
809  return status;
810 }
811 
814  unsigned char *buf,
815  ULONG buf_len,
816  ULONG *len)
817 {
819  ULONG header_len = 0;
820  unsigned char *tmp = buf;
821 
822  status = marshal_nfs41_header(entry, tmp, buf_len, len);
823  if (status) goto out;
824  else tmp += *len;
825 
826  header_len = *len + 2 * sizeof(LONGLONG) + 2 * sizeof(BOOLEAN);
827  if (header_len > buf_len) {
829  goto out;
830  }
831  RtlCopyMemory(tmp, &entry->u.Lock.offset, sizeof(LONGLONG));
832  tmp += sizeof(LONGLONG);
833  RtlCopyMemory(tmp, &entry->u.Lock.length, sizeof(LONGLONG));
834  tmp += sizeof(LONGLONG);
835  RtlCopyMemory(tmp, &entry->u.Lock.exclusive, sizeof(BOOLEAN));
836  tmp += sizeof(BOOLEAN);
837  RtlCopyMemory(tmp, &entry->u.Lock.blocking, sizeof(BOOLEAN));
838  *len = header_len;
839 
840 #ifdef DEBUG_MARSHAL_DETAIL
841  DbgP("marshal_nfs41_lock: offset=%llx length=%llx exclusive=%u "
842  "blocking=%u\n", entry->u.Lock.offset, entry->u.Lock.length,
843  entry->u.Lock.exclusive, entry->u.Lock.blocking);
844 #endif
845 out:
846  return status;
847 }
848 
851  unsigned char *buf,
852  ULONG buf_len,
853  ULONG *len)
854 {
856  ULONG header_len = 0;
857  unsigned char *tmp = buf;
859 
860  status = marshal_nfs41_header(entry, tmp, buf_len, len);
861  if (status) goto out;
862  else tmp += *len;
863 
864  header_len = *len + sizeof(ULONG) +
865  entry->u.Unlock.count * 2 * sizeof(LONGLONG);
866  if (header_len > buf_len) {
868  goto out;
869  }
870  RtlCopyMemory(tmp, &entry->u.Unlock.count, sizeof(ULONG));
871  tmp += sizeof(ULONG);
872 
873  lock = &entry->u.Unlock.locks;
874  while (lock) {
875  RtlCopyMemory(tmp, &lock->ByteOffset, sizeof(LONGLONG));
876  tmp += sizeof(LONGLONG);
877  RtlCopyMemory(tmp, &lock->Length, sizeof(LONGLONG));
878  tmp += sizeof(LONGLONG);
879  lock = lock->Next;
880  }
881  *len = header_len;
882 
883 #ifdef DEBUG_MARSHAL_DETAIL
884  DbgP("marshal_nfs41_unlock: count=%u\n", entry->u.Unlock.count);
885 #endif
886 out:
887  return status;
888 }
889 
892  unsigned char *buf,
893  ULONG buf_len,
894  ULONG *len)
895 {
897  ULONG header_len = 0;
898  unsigned char *tmp = buf;
899 
900  status = marshal_nfs41_header(entry, tmp, buf_len, len);
901  if (status) goto out;
902  else tmp += *len;
903 
904  header_len = *len + sizeof(BOOLEAN) + sizeof(HANDLE);
905  if (entry->u.Close.remove)
906  header_len += length_as_utf8(entry->filename) +
907  sizeof(BOOLEAN);
908 
909  if (header_len > buf_len) {
911  goto out;
912  }
913  RtlCopyMemory(tmp, &entry->u.Close.remove, sizeof(BOOLEAN));
914  tmp += sizeof(BOOLEAN);
915  RtlCopyMemory(tmp, &entry->u.Close.srv_open, sizeof(HANDLE));
916  if (entry->u.Close.remove) {
917  tmp += sizeof(HANDLE);
918  status = marshall_unicode_as_utf8(&tmp, entry->filename);
919  if (status) goto out;
920  RtlCopyMemory(tmp, &entry->u.Close.renamed, sizeof(BOOLEAN));
921  }
922  *len = header_len;
923 
924 #ifdef DEBUG_MARSHAL_DETAIL
925  DbgP("marshal_nfs41_close: name=%wZ remove=%d srv_open=%p renamed=%d\n",
926  entry->filename->Length?entry->filename:&SLASH,
927  entry->u.Close.remove, entry->u.Close.srv_open, entry->u.Close.renamed);
928 #endif
929 out:
930  return status;
931 }
932 
935  unsigned char *buf,
936  ULONG buf_len,
937  ULONG *len)
938 {
940  ULONG header_len = 0;
941  unsigned char *tmp = buf;
942 
943  status = marshal_nfs41_header(entry, tmp, buf_len, len);
944  if (status) goto out;
945  else tmp += *len;
946 
947  header_len = *len + 2 * sizeof(ULONG) + sizeof(HANDLE) +
948  length_as_utf8(entry->u.QueryFile.filter) + 3 * sizeof(BOOLEAN);
949  if (header_len > buf_len) {
951  goto out;
952  }
953 
954  RtlCopyMemory(tmp, &entry->u.QueryFile.InfoClass, sizeof(ULONG));
955  tmp += sizeof(ULONG);
956  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
957  tmp += sizeof(ULONG);
958  status = marshall_unicode_as_utf8(&tmp, entry->u.QueryFile.filter);
959  if (status) goto out;
960  RtlCopyMemory(tmp, &entry->u.QueryFile.initial_query, sizeof(BOOLEAN));
961  tmp += sizeof(BOOLEAN);
962  RtlCopyMemory(tmp, &entry->u.QueryFile.restart_scan, sizeof(BOOLEAN));
963  tmp += sizeof(BOOLEAN);
964  RtlCopyMemory(tmp, &entry->u.QueryFile.return_single, sizeof(BOOLEAN));
965  tmp += sizeof(BOOLEAN);
966  _SEH2_TRY {
967  entry->u.QueryFile.mdl_buf =
969 #ifndef __REACTOS__
971 #else
973 #endif
974  if (entry->u.QueryFile.mdl_buf == NULL) {
975  print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
977  goto out;
978  }
980  NTSTATUS code;
981  code = _SEH2_GetExceptionCode();
982  print_error("Call to MmMapLocked failed due to exception 0x%x\n", code);
983  status = STATUS_ACCESS_DENIED;
984  goto out;
985  } _SEH2_END;
986  RtlCopyMemory(tmp, &entry->u.QueryFile.mdl_buf, sizeof(HANDLE));
987  *len = header_len;
988 
989 #ifdef DEBUG_MARSHAL_DETAIL
990  DbgP("marshal_nfs41_dirquery: filter='%wZ'class=%d len=%d "
991  "1st\\restart\\single=%d\\%d\\%d\n", entry->u.QueryFile.filter,
992  entry->u.QueryFile.InfoClass, entry->buf_len,
993  entry->u.QueryFile.initial_query, entry->u.QueryFile.restart_scan,
994  entry->u.QueryFile.return_single);
995 #endif
996 out:
997  return status;
998 }
999 
1002  unsigned char *buf,
1003  ULONG buf_len,
1004  ULONG *len)
1005 {
1007  ULONG header_len = 0;
1008  unsigned char *tmp = buf;
1009 
1010  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1011  if (status) goto out;
1012  else tmp += *len;
1013 
1014  header_len = *len + 2 * sizeof(ULONG);
1015  if (header_len > buf_len) {
1017  goto out;
1018  }
1019  RtlCopyMemory(tmp, &entry->u.QueryFile.InfoClass, sizeof(ULONG));
1020  tmp += sizeof(ULONG);
1021  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
1022  tmp += sizeof(ULONG);
1023  RtlCopyMemory(tmp, &entry->session, sizeof(HANDLE));
1024  tmp += sizeof(HANDLE);
1025  RtlCopyMemory(tmp, &entry->open_state, sizeof(HANDLE));
1026  *len = header_len;
1027 
1028 #ifdef DEBUG_MARSHAL_DETAIL
1029  DbgP("marshal_nfs41_filequery: class=%d\n", entry->u.QueryFile.InfoClass);
1030 #endif
1031 out:
1032  return status;
1033 }
1034 
1037  unsigned char *buf,
1038  ULONG buf_len,
1039  ULONG *len)
1040 {
1042  ULONG header_len = 0;
1043  unsigned char *tmp = buf;
1044 
1045  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1046  if (status) goto out;
1047  else tmp += *len;
1048 
1049  header_len = *len + length_as_utf8(entry->filename) +
1050  2 * sizeof(ULONG) + entry->buf_len;
1051  if (header_len > buf_len) {
1053  goto out;
1054  }
1055  status = marshall_unicode_as_utf8(&tmp, entry->filename);
1056  if (status) goto out;
1057  RtlCopyMemory(tmp, &entry->u.SetFile.InfoClass, sizeof(ULONG));
1058  tmp += sizeof(ULONG);
1059  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
1060  tmp += sizeof(ULONG);
1061  RtlCopyMemory(tmp, entry->buf, entry->buf_len);
1062  *len = header_len;
1063 
1064 #ifdef DEBUG_MARSHAL_DETAIL
1065  DbgP("marshal_nfs41_fileset: filename='%wZ' class=%d\n",
1066  entry->filename, entry->u.SetFile.InfoClass);
1067 #endif
1068 out:
1069  return status;
1070 }
1071 
1074  unsigned char *buf,
1075  ULONG buf_len,
1076  ULONG *len)
1077 {
1079  ULONG header_len = 0;
1080  unsigned char *tmp = buf;
1081 
1082  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1083  if (status) goto out;
1084  else tmp += *len;
1085 
1086  header_len = *len + length_as_utf8(entry->filename) +
1087  sizeof(ULONG) + entry->buf_len + sizeof(DWORD);
1088  if (header_len > buf_len) {
1090  goto out;
1091  }
1092 
1093  status = marshall_unicode_as_utf8(&tmp, entry->filename);
1094  if (status) goto out;
1095  RtlCopyMemory(tmp, &entry->u.SetEa.mode, sizeof(DWORD));
1096  tmp += sizeof(DWORD);
1097  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
1098  tmp += sizeof(ULONG);
1099  RtlCopyMemory(tmp, entry->buf, entry->buf_len);
1100  *len = header_len;
1101 
1102 #ifdef DEBUG_MARSHAL_DETAIL
1103  DbgP("marshal_nfs41_easet: filename=%wZ, buflen=%d mode=0x%x\n",
1104  entry->filename, entry->buf_len, entry->u.SetEa.mode);
1105 #endif
1106 out:
1107  return status;
1108 }
1109 
1112  unsigned char *buf,
1113  ULONG buf_len,
1114  ULONG *len)
1115 {
1117  ULONG header_len = 0;
1118  unsigned char *tmp = buf;
1119 
1120  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1121  if (status) goto out;
1122  else tmp += *len;
1123 
1124  header_len = *len + length_as_utf8(entry->filename) +
1125  3 * sizeof(ULONG) + entry->u.QueryEa.EaListLength + 2 * sizeof(BOOLEAN);
1126 
1127  if (header_len > buf_len) {
1129  goto out;
1130  }
1131 
1132  status = marshall_unicode_as_utf8(&tmp, entry->filename);
1133  if (status) goto out;
1134  RtlCopyMemory(tmp, &entry->u.QueryEa.EaIndex, sizeof(ULONG));
1135  tmp += sizeof(ULONG);
1136  RtlCopyMemory(tmp, &entry->u.QueryEa.RestartScan, sizeof(BOOLEAN));
1137  tmp += sizeof(BOOLEAN);
1138  RtlCopyMemory(tmp, &entry->u.QueryEa.ReturnSingleEntry, sizeof(BOOLEAN));
1139  tmp += sizeof(BOOLEAN);
1140  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
1141  tmp += sizeof(ULONG);
1142  RtlCopyMemory(tmp, &entry->u.QueryEa.EaListLength, sizeof(ULONG));
1143  tmp += sizeof(ULONG);
1144  if (entry->u.QueryEa.EaList && entry->u.QueryEa.EaListLength)
1145  RtlCopyMemory(tmp, entry->u.QueryEa.EaList,
1146  entry->u.QueryEa.EaListLength);
1147  *len = header_len;
1148 
1149 #ifdef DEBUG_MARSHAL_DETAIL
1150  DbgP("marshal_nfs41_eaget: filename=%wZ, index=%d list_len=%d "
1151  "rescan=%d single=%d\n", entry->filename,
1152  entry->u.QueryEa.EaIndex, entry->u.QueryEa.EaListLength,
1153  entry->u.QueryEa.RestartScan, entry->u.QueryEa.ReturnSingleEntry);
1154 #endif
1155 out:
1156  return status;
1157 }
1158 
1161  unsigned char *buf,
1162  ULONG buf_len,
1163  ULONG *len)
1164 {
1166  ULONG header_len = 0;
1167  unsigned char *tmp = buf;
1168 
1169  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1170  if (status) goto out;
1171  else tmp += *len;
1172 
1173  header_len = *len + sizeof(BOOLEAN) + length_as_utf8(entry->filename);
1174  if (entry->u.Symlink.set)
1175  header_len += length_as_utf8(entry->u.Symlink.target);
1176  if (header_len > buf_len) {
1178  goto out;
1179  }
1180 
1181  status = marshall_unicode_as_utf8(&tmp, entry->filename);
1182  if (status) goto out;
1183  RtlCopyMemory(tmp, &entry->u.Symlink.set, sizeof(BOOLEAN));
1184  tmp += sizeof(BOOLEAN);
1185  if (entry->u.Symlink.set) {
1186  status = marshall_unicode_as_utf8(&tmp, entry->u.Symlink.target);
1187  if (status) goto out;
1188  }
1189  *len = header_len;
1190 
1191 #ifdef DEBUG_MARSHAL_DETAIL
1192  DbgP("marshal_nfs41_symlink: name %wZ symlink target %wZ\n",
1193  entry->filename,
1194  entry->u.Symlink.set?entry->u.Symlink.target : NULL);
1195 #endif
1196 out:
1197  return status;
1198 }
1199 
1202  unsigned char *buf,
1203  ULONG buf_len,
1204  ULONG *len)
1205 {
1207  ULONG header_len = 0;
1208  unsigned char *tmp = buf;
1209 
1210  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1211  if (status) goto out;
1212  else tmp += *len;
1213 
1214  header_len = *len + sizeof(FS_INFORMATION_CLASS);
1215  if (header_len > buf_len) {
1217  goto out;
1218  }
1219 
1220  RtlCopyMemory(tmp, &entry->u.Volume.query, sizeof(FS_INFORMATION_CLASS));
1221  *len = header_len;
1222 
1223 #ifdef DEBUG_MARSHAL_DETAIL
1224  DbgP("marshal_nfs41_volume: class=%d\n", entry->u.Volume.query);
1225 #endif
1226 out:
1227  return status;
1228 }
1229 
1232  unsigned char *buf,
1233  ULONG buf_len,
1234  ULONG *len)
1235 {
1237  ULONG header_len = 0;
1238  unsigned char *tmp = buf;
1239 
1240  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1241  if (status) goto out;
1242  else tmp += *len;
1243 
1244  header_len = *len + sizeof(SECURITY_INFORMATION);
1245  if (header_len > buf_len) {
1247  goto out;
1248  }
1249 
1250  RtlCopyMemory(tmp, &entry->u.Acl.query, sizeof(SECURITY_INFORMATION));
1251  *len = header_len;
1252 
1253 #ifdef DEBUG_MARSHAL_DETAIL
1254  DbgP("marshal_nfs41_getacl: class=0x%x\n", entry->u.Acl.query);
1255 #endif
1256 out:
1257  return status;
1258 }
1259 
1262  unsigned char *buf,
1263  ULONG buf_len,
1264  ULONG *len)
1265 {
1267  ULONG header_len = 0;
1268  unsigned char *tmp = buf;
1269 
1270  status = marshal_nfs41_header(entry, tmp, buf_len, len);
1271  if (status) goto out;
1272  else tmp += *len;
1273 
1274  header_len = *len + sizeof(SECURITY_INFORMATION) +
1275  sizeof(ULONG) + entry->buf_len;
1276  if (header_len > buf_len) {
1278  goto out;
1279  }
1280 
1281  RtlCopyMemory(tmp, &entry->u.Acl.query, sizeof(SECURITY_INFORMATION));
1282  tmp += sizeof(SECURITY_INFORMATION);
1283  RtlCopyMemory(tmp, &entry->buf_len, sizeof(ULONG));
1284  tmp += sizeof(ULONG);
1285  RtlCopyMemory(tmp, entry->buf, entry->buf_len);
1286  *len = header_len;
1287 
1288 #ifdef DEBUG_MARSHAL_DETAIL
1289  DbgP("marshal_nfs41_setacl: class=0x%x sec_desc_len=%lu\n",
1290  entry->u.Acl.query, entry->buf_len);
1291 #endif
1292 out:
1293  return status;
1294 }
1295 
1298  unsigned char *buf,
1299  ULONG buf_len,
1300  ULONG *len)
1301 {
1302  return marshal_nfs41_header(entry, buf, buf_len, len);
1303 }
1304 
1306  IN PRX_CONTEXT RxContext)
1307 {
1308  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
1309  unsigned char *buf = LowIoContext->ParamsFor.IoCtl.pInputBuffer;
1311  PMRX_SRV_OPEN srv_open;
1312 
1313  RtlCopyMemory(&srv_open, buf, sizeof(HANDLE));
1314 #ifdef DEBUG_INVALIDATE_CACHE
1315  DbgP("nfs41_invalidate_cache: received srv_open=%p %wZ\n",
1316  srv_open, srv_open->pAlreadyPrefixedName);
1317 #endif
1318  if (MmIsAddressValid(srv_open))
1320  srv_open->pFcb->pNetRoot->pSrvCall, srv_open,
1321  srv_open->Key, ULongToPtr(flag));
1322 }
1323 
1325  IN PRX_CONTEXT RxContext,
1327  OUT ULONG *len)
1328 {
1330  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
1331  ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
1332  unsigned char *pbOut = LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
1333 
1334  status = SeImpersonateClientEx(entry->psec_ctx, NULL);
1335  if (status != STATUS_SUCCESS) {
1336  print_error("SeImpersonateClientEx failed %x\n", status);
1337  goto out;
1338  }
1339 
1340  switch(entry->opcode) {
1341  case NFS41_SHUTDOWN:
1342  status = marshal_nfs41_shutdown(entry, pbOut, cbOut, len);
1343  KeSetEvent(&entry->cond, 0, FALSE);
1344  break;
1345  case NFS41_MOUNT:
1346  status = marshal_nfs41_mount(entry, pbOut, cbOut, len);
1347  break;
1348  case NFS41_UNMOUNT:
1349  status = marshal_nfs41_unmount(entry, pbOut, cbOut, len);
1350  break;
1351  case NFS41_OPEN:
1352  status = marshal_nfs41_open(entry, pbOut, cbOut, len);
1353  break;
1354  case NFS41_READ:
1355  status = marshal_nfs41_rw(entry, pbOut, cbOut, len);
1356  break;
1357  case NFS41_WRITE:
1358  status = marshal_nfs41_rw(entry, pbOut, cbOut, len);
1359  break;
1360  case NFS41_LOCK:
1361  status = marshal_nfs41_lock(entry, pbOut, cbOut, len);
1362  break;
1363  case NFS41_UNLOCK:
1364  status = marshal_nfs41_unlock(entry, pbOut, cbOut, len);
1365  break;
1366  case NFS41_CLOSE:
1367  status = marshal_nfs41_close(entry, pbOut, cbOut, len);
1368  break;
1369  case NFS41_DIR_QUERY:
1370  status = marshal_nfs41_dirquery(entry, pbOut, cbOut, len);
1371  break;
1372  case NFS41_FILE_QUERY:
1373  status = marshal_nfs41_filequery(entry, pbOut, cbOut, len);
1374  break;
1375  case NFS41_FILE_SET:
1376  status = marshal_nfs41_fileset(entry, pbOut, cbOut, len);
1377  break;
1378  case NFS41_EA_SET:
1379  status = marshal_nfs41_easet(entry, pbOut, cbOut, len);
1380  break;
1381  case NFS41_EA_GET:
1382  status = marshal_nfs41_eaget(entry, pbOut, cbOut, len);
1383  break;
1384  case NFS41_SYMLINK:
1385  status = marshal_nfs41_symlink(entry, pbOut, cbOut, len);
1386  break;
1387  case NFS41_VOLUME_QUERY:
1388  status = marshal_nfs41_volume(entry, pbOut, cbOut, len);
1389  break;
1390  case NFS41_ACL_QUERY:
1391  status = marshal_nfs41_getacl(entry, pbOut, cbOut, len);
1392  break;
1393  case NFS41_ACL_SET:
1394  status = marshal_nfs41_setacl(entry, pbOut, cbOut, len);
1395  break;
1396  default:
1397  status = STATUS_INVALID_PARAMETER;
1398  print_error("Unknown nfs41 ops %d\n", entry->opcode);
1399  }
1400 
1401  if (status == STATUS_SUCCESS)
1402  print_hexbuf(0, (unsigned char *)"upcall buffer", pbOut, *len);
1403 
1404 out:
1405  return status;
1406 }
1407 
1409  IN DWORD opcode,
1410  IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx,
1411  IN HANDLE session,
1412  IN HANDLE open_state,
1413  IN DWORD version,
1415  OUT nfs41_updowncall_entry **entry_out)
1416 {
1419  SECURITY_SUBJECT_CONTEXT sec_ctx;
1421 
1424  if (entry == NULL) {
1426  goto out;
1427  }
1428 
1429  RtlZeroMemory(entry, sizeof(nfs41_updowncall_entry));
1430  entry->xid = InterlockedIncrement64(&xid);
1431  entry->opcode = opcode;
1433  entry->session = session;
1434  entry->open_state = open_state;
1435  entry->version = version;
1436  if (filename && filename->Length) entry->filename = filename;
1437  else if (filename && !filename->Length) entry->filename = (PUNICODE_STRING)&SLASH;
1438  else entry->filename = (PUNICODE_STRING)&EMPTY_STRING;
1439  /*XXX KeInitializeEvent will bugcheck under verifier if allocated
1440  * from PagedPool? */
1442  ExInitializeFastMutex(&entry->lock);
1443 
1444  if (clnt_sec_ctx == NULL) {
1445  SeCaptureSubjectContext(&sec_ctx);
1448  sec_qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
1449  sec_qos.EffectiveOnly = 0;
1450  status = SeCreateClientSecurityFromSubjectContext(&sec_ctx, &sec_qos,
1451  1, &entry->sec_ctx);
1452  if (status != STATUS_SUCCESS) {
1453  print_error("nfs41_UpcallCreate: "
1454  "SeCreateClientSecurityFromSubjectContext failed with %x\n",
1455  status);
1456  RxFreePool(entry);
1457  } else
1458  entry->psec_ctx = &entry->sec_ctx;
1459  SeReleaseSubjectContext(&sec_ctx);
1460  } else
1461  entry->psec_ctx = clnt_sec_ctx;
1462 
1463  *entry_out = entry;
1464 out:
1465  return status;
1466 }
1467 
1470  IN DWORD secs)
1471 {
1473 
1474  nfs41_AddEntry(upcallLock, upcall, entry);
1475  KeSetEvent(&upcallEvent, 0, FALSE);
1476  if (!entry->async_op) {
1478  timeout.QuadPart = RELATIVE(SECONDS(secs));
1479  /* 02/03/2011 AGLO: it is not clear what the "right" waiting design
1480  * should be. Having non-interruptable waiting seems to be the right
1481  * approach. However, when things go wrong, the only wait to proceed
1482  * is a reboot (since "waits" are not interruptable we can't stop a
1483  * hung task. Having interruptable wait causes issues with security
1484  * context. For now, I'm making CLOSE non-interruptable but keeping
1485  * the rest interruptable so that we don't have to reboot all the time
1486  */
1487  /* 02/15/2011 cbodley: added NFS41_UNLOCK for the same reason. locking
1488  * tests were triggering an interrupted unlock, which led to a bugcheck
1489  * in CloseSrvOpen() */
1490 #define MAKE_WAITONCLOSE_NONITERRUPTABLE
1491 #ifdef MAKE_WAITONCLOSE_NONITERRUPTABLE
1492  if (entry->opcode == NFS41_CLOSE || entry->opcode == NFS41_UNLOCK)
1493  status = KeWaitForSingleObject(&entry->cond, Executive,
1494  KernelMode, FALSE, &timeout);
1495  else {
1496  status = KeWaitForSingleObject(&entry->cond, Executive,
1497  UserMode, TRUE, &timeout);
1498  }
1499  if (status != STATUS_SUCCESS) {
1500  print_wait_status(1, "[downcall]", status,
1501  opcode2string(entry->opcode), entry, entry->xid);
1502  if (status == STATUS_TIMEOUT)
1503  status = STATUS_NETWORK_UNREACHABLE;
1504  }
1505 #else
1506 
1507  status = KeWaitForSingleObject(&entry->cond, Executive, KernelMode, FALSE, NULL);
1508 #endif
1509  print_wait_status(0, "[downcall]", status, opcode2string(entry->opcode),
1510  entry, entry->xid);
1511  } else
1512  goto out;
1513 
1514  switch(status) {
1515  case STATUS_SUCCESS: break;
1516  case STATUS_USER_APC:
1517  case STATUS_ALERTED:
1518  default:
1519  ExAcquireFastMutex(&entry->lock);
1520  if (entry->state == NFS41_DONE_PROCESSING) {
1521  ExReleaseFastMutex(&entry->lock);
1522  break;
1523  }
1524  DbgP("[upcall] abandoning %s entry=%p xid=%lld\n",
1525  opcode2string(entry->opcode), entry, entry->xid);
1526  entry->state = NFS41_NOT_WAITING;
1527  ExReleaseFastMutex(&entry->lock);
1528  goto out;
1529  }
1531 out:
1532  return status;
1533 }
1534 
1536  IN PRX_CONTEXT RxContext)
1537 {
1540  ULONG len = 0;
1541  PLIST_ENTRY pEntry;
1542 
1543 process_upcall:
1544  nfs41_RemoveFirst(upcallLock, upcall, pEntry);
1545  if (pEntry) {
1546  entry = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry,
1548  ExAcquireFastMutex(&entry->lock);
1549  nfs41_AddEntry(downcallLock, downcall, entry);
1550  status = handle_upcall(RxContext, entry, &len);
1551  if (status == STATUS_SUCCESS &&
1552  entry->state == NFS41_WAITING_FOR_UPCALL)
1554  ExReleaseFastMutex(&entry->lock);
1555  if (status) {
1556  entry->status = status;
1557  KeSetEvent(&entry->cond, 0, FALSE);
1558  RxContext->InformationToReturn = 0;
1559  } else
1560  RxContext->InformationToReturn = len;
1561  }
1562  else {
1563  status = KeWaitForSingleObject(&upcallEvent, Executive, UserMode, TRUE,
1564  (PLARGE_INTEGER) NULL);
1565  print_wait_status(0, "[upcall]", status, NULL, NULL, 0);
1566  switch (status) {
1567  case STATUS_SUCCESS: goto process_upcall;
1568  case STATUS_USER_APC:
1569  case STATUS_ALERTED:
1570  default: goto out;
1571  }
1572  }
1573 out:
1574  return status;
1575 }
1576 
1579  unsigned char **buf)
1580 {
1581  RtlZeroMemory(tmp, sizeof(nfs41_updowncall_entry));
1582 
1583  RtlCopyMemory(&tmp->xid, *buf, sizeof(tmp->xid));
1584  *buf += sizeof(tmp->xid);
1585  RtlCopyMemory(&tmp->opcode, *buf, sizeof(tmp->opcode));
1586  *buf += sizeof(tmp->opcode);
1587  RtlCopyMemory(&tmp->status, *buf, sizeof(tmp->status));
1588  *buf += sizeof(tmp->status);
1589  RtlCopyMemory(&tmp->errno, *buf, sizeof(tmp->errno));
1590  *buf += sizeof(tmp->errno);
1591 #ifdef DEBUG_MARSHAL_HEADER
1592  DbgP("[downcall header] xid=%lld opcode=%s status=%d errno=%d\n", tmp->xid,
1593  opcode2string(tmp->opcode), tmp->status, tmp->errno);
1594 #endif
1595 }
1596 
1599  unsigned char **buf)
1600 {
1601  RtlCopyMemory(&cur->session, *buf, sizeof(HANDLE));
1602  *buf += sizeof(HANDLE);
1603  RtlCopyMemory(&cur->version, *buf, sizeof(DWORD));
1604  *buf += sizeof(DWORD);
1605  RtlCopyMemory(&cur->u.Mount.lease_time, *buf, sizeof(DWORD));
1606  *buf += sizeof(DWORD);
1607  RtlCopyMemory(cur->u.Mount.FsAttrs, *buf, sizeof(FILE_FS_ATTRIBUTE_INFORMATION));
1608 #ifdef DEBUG_MARSHAL_DETAIL
1609  DbgP("unmarshal_nfs41_mount: session pointer 0x%x version %d lease_time "
1610  "%d\n", cur->session, cur->version, cur->u.Mount.lease_time);
1611 #endif
1612 }
1613 
1616  PULONGLONG dest_buf,
1617  unsigned char **buf)
1618 {
1619  RtlCopyMemory(dest_buf, *buf, sizeof(ULONGLONG));
1620 #ifdef DEBUG_MARSHAL_DETAIL
1621  DbgP("unmarshal_nfs41_setattr: returned ChangeTime %llu\n", *dest_buf);
1622 #endif
1623 }
1624 
1627  unsigned char **buf)
1628 {
1630 
1631  RtlCopyMemory(&cur->buf_len, *buf, sizeof(cur->buf_len));
1632  *buf += sizeof(cur->buf_len);
1633  RtlCopyMemory(&cur->ChangeTime, *buf, sizeof(ULONGLONG));
1634 #ifdef DEBUG_MARSHAL_DETAIL
1635  DbgP("unmarshal_nfs41_rw: returned len %lu ChangeTime %llu\n",
1636  cur->buf_len, cur->ChangeTime);
1637 #endif
1638 #if 1
1639  /* 08/27/2010: it looks like we really don't need to call
1640  * MmUnmapLockedPages() eventhough we called
1641  * MmMapLockedPagesSpecifyCache() as the MDL passed to us
1642  * is already locked.
1643  */
1644  _SEH2_TRY {
1645  MmUnmapLockedPages(cur->buf, cur->u.ReadWrite.MdlAddress);
1647  NTSTATUS code;
1648  code = _SEH2_GetExceptionCode();
1649  print_error("Call to MmUnmapLockedPages failed due to"
1650  " exception 0x%0x\n", code);
1651  status = STATUS_ACCESS_DENIED;
1652  } _SEH2_END;
1653 #endif
1654  return status;
1655 }
1656 
1659  unsigned char **buf)
1660 {
1662 
1663  _SEH2_TRY {
1664  if (cur->u.Open.EaBuffer)
1665  MmUnmapLockedPages(cur->u.Open.EaBuffer, cur->u.Open.EaMdl);
1667  print_error("MmUnmapLockedPages thrown exception=0x%0x\n", _SEH2_GetExceptionCode());
1668  status = cur->status = STATUS_ACCESS_DENIED;
1669  goto out;
1670  } _SEH2_END;
1671 
1672  RtlCopyMemory(&cur->u.Open.binfo, *buf, sizeof(FILE_BASIC_INFORMATION));
1673  *buf += sizeof(FILE_BASIC_INFORMATION);
1674  RtlCopyMemory(&cur->u.Open.sinfo, *buf, sizeof(FILE_STANDARD_INFORMATION));
1675  *buf += sizeof(FILE_STANDARD_INFORMATION);
1676  RtlCopyMemory(&cur->open_state, *buf, sizeof(HANDLE));
1677  *buf += sizeof(HANDLE);
1678  RtlCopyMemory(&cur->u.Open.mode, *buf, sizeof(DWORD));
1679  *buf += sizeof(DWORD);
1680  RtlCopyMemory(&cur->ChangeTime, *buf, sizeof(ULONGLONG));
1681  *buf += sizeof(ULONGLONG);
1682  RtlCopyMemory(&cur->u.Open.deleg_type, *buf, sizeof(DWORD));
1683  *buf += sizeof(DWORD);
1684  if (cur->errno == ERROR_REPARSE) {
1685  RtlCopyMemory(&cur->u.Open.symlink_embedded, *buf, sizeof(BOOLEAN));
1686  *buf += sizeof(BOOLEAN);
1687  RtlCopyMemory(&cur->u.Open.symlink.MaximumLength, *buf,
1688  sizeof(USHORT));
1689  *buf += sizeof(USHORT);
1690  cur->u.Open.symlink.Length = cur->u.Open.symlink.MaximumLength -
1691  sizeof(WCHAR);
1692  cur->u.Open.symlink.Buffer = RxAllocatePoolWithTag(NonPagedPool,
1693  cur->u.Open.symlink.MaximumLength, NFS41_MM_POOLTAG);
1694  if (cur->u.Open.symlink.Buffer == NULL) {
1696  status = STATUS_UNSUCCESSFUL;
1697  goto out;
1698  }
1699  RtlCopyMemory(cur->u.Open.symlink.Buffer, *buf,
1700  cur->u.Open.symlink.MaximumLength);
1701 #ifdef DEBUG_MARSHAL_DETAIL
1702  DbgP("unmarshal_nfs41_open: ERROR_REPARSE -> '%wZ'\n", &cur->u.Open.symlink);
1703 #endif
1704  }
1705 #ifdef DEBUG_MARSHAL_DETAIL
1706  DbgP("unmarshal_nfs41_open: open_state 0x%x mode %o changeattr %llu "
1707  "deleg_type %d\n", cur->open_state, cur->u.Open.mode,
1708  cur->ChangeTime, cur->u.Open.deleg_type);
1709 #endif
1710 out:
1711  return status;
1712 }
1713 
1716  unsigned char **buf)
1717 {
1719  ULONG buf_len;
1720 
1721  RtlCopyMemory(&buf_len, *buf, sizeof(ULONG));
1722 #ifdef DEBUG_MARSHAL_DETAIL
1723  DbgP("unmarshal_nfs41_dirquery: reply size %d\n", buf_len);
1724 #endif
1725  *buf += sizeof(ULONG);
1726  _SEH2_TRY {
1727  MmUnmapLockedPages(cur->u.QueryFile.mdl_buf, cur->u.QueryFile.mdl);
1729  NTSTATUS code;
1730  code = _SEH2_GetExceptionCode();
1731  print_error("MmUnmapLockedPages thrown exception=0x%0x\n", code);
1732  status = STATUS_ACCESS_DENIED;
1733  } _SEH2_END;
1734  if (buf_len > cur->buf_len)
1736  cur->buf_len = buf_len;
1737 
1738  return status;
1739 }
1740 
1743  PVOID attr_value,
1744  ULONG *attr_len,
1745  unsigned char **buf)
1746 {
1747  ULONG buf_len;
1748  RtlCopyMemory(&buf_len, *buf, sizeof(ULONG));
1749  if (buf_len > *attr_len) {
1751  return;
1752  }
1753  *buf += sizeof(ULONG);
1754  *attr_len = buf_len;
1755  RtlCopyMemory(attr_value, *buf, buf_len);
1756  *buf += buf_len;
1757 }
1758 
1761  unsigned char **buf)
1762 {
1763  RtlCopyMemory(&cur->u.QueryEa.Overflow, *buf, sizeof(ULONG));
1764  *buf += sizeof(ULONG);
1765  RtlCopyMemory(&cur->buf_len, *buf, sizeof(ULONG));
1766  *buf += sizeof(ULONG);
1767  if (cur->u.QueryEa.Overflow != ERROR_INSUFFICIENT_BUFFER) {
1768  RtlCopyMemory(cur->buf, *buf, cur->buf_len);
1769  *buf += cur->buf_len;
1770  }
1771 }
1772 
1775  unsigned char **buf)
1776 {
1777  unmarshal_nfs41_attrget(cur, cur->buf, &cur->buf_len, buf);
1778  RtlCopyMemory(&cur->ChangeTime, *buf, sizeof(LONGLONG));
1779 #ifdef DEBUG_MARSHAL_DETAIL
1780  if (cur->u.QueryFile.InfoClass == FileBasicInformation)
1781  DbgP("[unmarshal_nfs41_getattr] ChangeTime %llu\n", cur->ChangeTime);
1782 #endif
1783 }
1784 
1787  unsigned char **buf)
1788 {
1790  DWORD buf_len;
1791 
1792  RtlCopyMemory(&buf_len, *buf, sizeof(DWORD));
1793  *buf += sizeof(DWORD);
1795  buf_len, NFS41_MM_POOLTAG_ACL);
1796  if (cur->buf == NULL) {
1797  cur->status = status = STATUS_INSUFFICIENT_RESOURCES;
1798  goto out;
1799  }
1800  RtlCopyMemory(cur->buf, *buf, buf_len);
1801  if (buf_len > cur->buf_len)
1803  cur->buf_len = buf_len;
1804 
1805 out:
1806  return status;
1807 }
1808 
1811  unsigned char **buf)
1812 {
1813  if (cur->u.Symlink.set) return;
1814 
1815  RtlCopyMemory(&cur->u.Symlink.target->Length, *buf, sizeof(USHORT));
1816  *buf += sizeof(USHORT);
1817  if (cur->u.Symlink.target->Length >
1818  cur->u.Symlink.target->MaximumLength) {
1820  return;
1821  }
1822  RtlCopyMemory(cur->u.Symlink.target->Buffer, *buf,
1823  cur->u.Symlink.target->Length);
1824  cur->u.Symlink.target->Length -= sizeof(UNICODE_NULL);
1825 }
1826 
1828  IN PRX_CONTEXT RxContext)
1829 {
1831  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
1832  ULONG in_len = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
1833  unsigned char *buf = LowIoContext->ParamsFor.IoCtl.pInputBuffer;
1834  PLIST_ENTRY pEntry;
1835  nfs41_updowncall_entry *tmp, *cur= NULL;
1836  BOOLEAN found = 0;
1837 
1838  print_hexbuf(0, (unsigned char *)"downcall buffer", buf, in_len);
1839 
1842  if (tmp == NULL) goto out;
1843 
1844  unmarshal_nfs41_header(tmp, &buf);
1845 
1847  pEntry = &downcall.head;
1848  pEntry = pEntry->Flink;
1849  while (pEntry != NULL) {
1850  cur = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry,
1852  if (cur->xid == tmp->xid) {
1853  found = 1;
1854  break;
1855  }
1856  if (pEntry->Flink == &downcall.head)
1857  break;
1858  pEntry = pEntry->Flink;
1859  }
1862  if (!found) {
1863  print_error("Didn't find xid=%lld entry\n", tmp->xid);
1864  goto out_free;
1865  }
1866 
1867  ExAcquireFastMutex(&cur->lock);
1868  if (cur->state == NFS41_NOT_WAITING) {
1869  DbgP("[downcall] Nobody is waiting for this request!!!\n");
1870  switch(cur->opcode) {
1871  case NFS41_WRITE:
1872  case NFS41_READ:
1873  MmUnmapLockedPages(cur->buf, cur->u.ReadWrite.MdlAddress);
1874  break;
1875  case NFS41_DIR_QUERY:
1876  MmUnmapLockedPages(cur->u.QueryFile.mdl_buf,
1877  cur->u.QueryFile.mdl);
1878  IoFreeMdl(cur->u.QueryFile.mdl);
1879  break;
1880  case NFS41_OPEN:
1881  if (cur->u.Open.EaMdl) {
1882  MmUnmapLockedPages(cur->u.Open.EaBuffer,
1883  cur->u.Open.EaMdl);
1884  IoFreeMdl(cur->u.Open.EaMdl);
1885  }
1886  break;
1887  }
1888  ExReleaseFastMutex(&cur->lock);
1890  RxFreePool(cur);
1891  status = STATUS_UNSUCCESSFUL;
1892  goto out_free;
1893  }
1895  cur->status = tmp->status;
1896  cur->errno = tmp->errno;
1897  status = STATUS_SUCCESS;
1898 
1899  if (!tmp->status) {
1900  switch (tmp->opcode) {
1901  case NFS41_MOUNT:
1902  unmarshal_nfs41_mount(cur, &buf);
1903  break;
1904  case NFS41_WRITE:
1905  case NFS41_READ:
1906  status = unmarshal_nfs41_rw(cur, &buf);
1907  break;
1908  case NFS41_OPEN:
1909  status = unmarshal_nfs41_open(cur, &buf);
1910  break;
1911  case NFS41_DIR_QUERY:
1912  status = unmarshal_nfs41_dirquery(cur, &buf);
1913  break;
1914  case NFS41_FILE_QUERY:
1915  unmarshal_nfs41_getattr(cur, &buf);
1916  break;
1917  case NFS41_EA_GET:
1918  unmarshal_nfs41_eaget(cur, &buf);
1919  break;
1920  case NFS41_SYMLINK:
1921  unmarshal_nfs41_symlink(cur, &buf);
1922  break;
1923  case NFS41_VOLUME_QUERY:
1924  unmarshal_nfs41_attrget(cur, cur->buf, &cur->buf_len, &buf);
1925  break;
1926  case NFS41_ACL_QUERY:
1927  status = unmarshal_nfs41_getacl(cur, &buf);
1928  break;
1929  case NFS41_FILE_SET:
1930  unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1931  break;
1932  case NFS41_EA_SET:
1933  unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1934  break;
1935  case NFS41_ACL_SET:
1936  unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1937  break;
1938  }
1939  }
1940  ExReleaseFastMutex(&cur->lock);
1941  if (cur->async_op) {
1942  if (cur->status == STATUS_SUCCESS) {
1943  cur->u.ReadWrite.rxcontext->StoredStatus = STATUS_SUCCESS;
1944  cur->u.ReadWrite.rxcontext->InformationToReturn =
1945  cur->buf_len;
1946  } else {
1947  cur->u.ReadWrite.rxcontext->StoredStatus =
1949  cur->u.ReadWrite.rxcontext->InformationToReturn = 0;
1950  }
1952  RxLowIoCompletion(cur->u.ReadWrite.rxcontext);
1953  RxFreePool(cur);
1954  } else
1955  KeSetEvent(&cur->cond, 0, FALSE);
1956 
1957 out_free:
1958  RxFreePool(tmp);
1959 out:
1960  return status;
1961 }
1962 
1964  DWORD version)
1965 {
1968 
1969  DbgEn();
1971  INVALID_HANDLE_VALUE, version, NULL, &entry);
1972  if (status) goto out;
1973 
1976  if (status) goto out;
1977 
1978  RxFreePool(entry);
1979 out:
1980  DbgEx();
1981  return status;
1982 }
1983 
1985  OUT PHANDLE phSection)
1986 {
1987  NTSTATUS status;
1988  HANDLE hSection;
1989  UNICODE_STRING SectionName;
1990  SECURITY_DESCRIPTOR SecurityDesc;
1991  OBJECT_ATTRIBUTES SectionAttrs;
1992  LARGE_INTEGER nSectionSize;
1993 
1994  DbgEn();
1995 
1997 
1998  /* XXX: setting dacl=NULL grants access to everyone */
1999  status = RtlCreateSecurityDescriptor(&SecurityDesc,
2001  if (status) {
2002  print_error("RtlCreateSecurityDescriptor() failed with %08X\n", status);
2003  goto out;
2004  }
2005  status = RtlSetDaclSecurityDescriptor(&SecurityDesc, TRUE, NULL, FALSE);
2006  if (status) {
2007  print_error("RtlSetDaclSecurityDescriptor() failed with %08X\n", status);
2008  goto out;
2009  }
2010 
2011  InitializeObjectAttributes(&SectionAttrs, &SectionName,
2012  0, NULL, &SecurityDesc);
2013 
2014  nSectionSize.QuadPart = sizeof(NFS41NP_SHARED_MEMORY);
2015 
2016  status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE,
2017  &SectionAttrs, &nSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);
2018  switch (status) {
2019  case STATUS_SUCCESS:
2020  break;
2022  DbgP("section already created; returning success\n");
2023  status = STATUS_SUCCESS;
2024  goto out;
2025  default:
2026  DbgP("ZwCreateSection failed with %08X\n", status);
2027  goto out;
2028  }
2029 out:
2030  DbgEx();
2031  return status;
2032 }
2033 
2035  IN HANDLE hSection)
2036 {
2037  NTSTATUS status;
2038  DbgEn();
2039  status = ZwClose(hSection);
2040  DbgEx();
2041  return status;
2042 }
2043 
2044 #ifdef __REACTOS__
2046 #else
2048 #endif
2049  IN OUT PRX_CONTEXT RxContext,
2051 {
2052  NTSTATUS status;
2053  NFS41GetDeviceExtension(RxContext, DevExt);
2054 
2055  DbgEn();
2056 
2057  status = SharedMemoryInit(&DevExt->SharedMemorySection);
2058  if (status) {
2059  print_error("InitSharedMemory failed with %08X\n", status);
2061  goto out;
2062  }
2063 
2064  InterlockedCompareExchange((PLONG)&nfs41_start_state,
2067 out:
2068  DbgEx();
2069  return status;
2070 }
2071 
2072 #ifdef __REACTOS__
2074 #else
2076 #endif
2077  IN OUT PRX_CONTEXT RxContext,
2079 {
2080  NTSTATUS status;
2081  NFS41GetDeviceExtension(RxContext, DevExt);
2082  DbgEn();
2083  status = SharedMemoryFree(DevExt->SharedMemorySection);
2084  DbgEx();
2085  return status;
2086 }
2087 
2089  IN PUNICODE_STRING ConnectionName,
2090  IN PVOID EaBuffer,
2091  IN ULONG EaLength,
2092  OUT PHANDLE Handle)
2093 {
2094  NTSTATUS status;
2097 
2098 #ifdef DEBUG_MOUNT
2099  DbgEn();
2100 #endif
2101  InitializeObjectAttributes(&ObjectAttributes, ConnectionName,
2103 
2104  print_error("Len %d Buf %p\n", EaLength, EaBuffer);
2105 
2106  status = ZwCreateFile(Handle, SYNCHRONIZE, &ObjectAttributes,
2107  &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
2109  FILE_OPEN_IF,
2111  EaBuffer, EaLength);
2112 
2113 #ifdef DEBUG_MOUNT
2114  DbgEx();
2115 #endif
2116  return status;
2117 }
2118 
2120  IN PVOID Buffer,
2121  IN ULONG BufferLen,
2122  OUT PUNICODE_STRING pConnectionName,
2123  OUT PVOID *ppEaBuffer,
2124  OUT PULONG pEaLength)
2125 {
2127  USHORT NameLength, EaPadding;
2128  ULONG EaLength, BufferLenExpected;
2129  PBYTE ptr;
2130 
2131  /* make sure buffer is at least big enough for header */
2132  if (BufferLen < sizeof(USHORT) + sizeof(USHORT) + sizeof(ULONG)) {
2133  status = STATUS_BAD_NETWORK_NAME;
2134  print_error("Invalid input buffer.\n");
2135  pConnectionName->Length = pConnectionName->MaximumLength = 0;
2136  *ppEaBuffer = NULL;
2137  *pEaLength = 0;
2138  goto out;
2139  }
2140 
2141  ptr = Buffer;
2142  NameLength = *(PUSHORT)ptr;
2143  ptr += sizeof(USHORT);
2144  EaPadding = *(PUSHORT)ptr;
2145  ptr += sizeof(USHORT);
2146  EaLength = *(PULONG)ptr;
2147  ptr += sizeof(ULONG);
2148 
2149  /* validate buffer length */
2150  BufferLenExpected = sizeof(USHORT) + sizeof(USHORT) + sizeof(ULONG) +
2151  NameLength + EaPadding + EaLength;
2152  if (BufferLen != BufferLenExpected) {
2153  status = STATUS_BAD_NETWORK_NAME;
2154  print_error("Received buffer of length %lu, but expected %lu bytes.\n",
2155  BufferLen, BufferLenExpected);
2156  pConnectionName->Length = pConnectionName->MaximumLength = 0;
2157  *ppEaBuffer = NULL;
2158  *pEaLength = 0;
2159  goto out;
2160  }
2161 
2162  pConnectionName->Buffer = (PWCH)ptr;
2163  pConnectionName->Length = NameLength - sizeof(WCHAR);
2164  pConnectionName->MaximumLength = NameLength;
2165 
2166  if (EaLength)
2167  *ppEaBuffer = ptr + NameLength + EaPadding;
2168  else
2169  *ppEaBuffer = NULL;
2170  *pEaLength = EaLength;
2171 
2172 out:
2173  return status;
2174 }
2175 
2177  IN PRX_CONTEXT RxContext,
2178  OUT PBOOLEAN PostToFsp)
2179 {
2182  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
2183  PVOID Buffer = LowIoContext->ParamsFor.IoCtl.pInputBuffer, EaBuffer;
2184  ULONG BufferLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength, EaLength;
2186  BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
2187 
2188 #ifdef DEBUG_MOUNT
2189  DbgEn();
2190 #endif
2191 
2192  if (!Wait) {
2193  //just post right now!
2194  DbgP("returning STATUS_PENDING\n");
2195  *PostToFsp = TRUE;
2196  status = STATUS_PENDING;
2197  goto out;
2198  }
2199 
2200  status = nfs41_GetConnectionInfoFromBuffer(Buffer, BufferLen,
2201  &FileName, &EaBuffer, &EaLength);
2202  if (status != STATUS_SUCCESS)
2203  goto out;
2204 
2205  status = GetConnectionHandle(&FileName, EaBuffer, EaLength, &Handle);
2206  if (!status && Handle != INVALID_HANDLE_VALUE)
2207  ZwClose(Handle);
2208 out:
2209 #ifdef DEBUG_MOUNT
2210  DbgEx();
2211 #endif
2212  return status;
2213 }
2214 
2215 #ifdef ENABLE_TIMINGS
2216 void print_op_stat(
2217  const char *op_str,
2218  nfs41_timings *time, BOOLEAN clear)
2219 {
2220  DbgP("%-9s: num_ops=%-10d delta_ticks=%-10d size=%-10d\n", op_str,
2221  time->tops, time->tops ? time->ticks/time->tops : 0,
2222  time->sops ? time->size/time->sops : 0);
2223  if (clear) {
2224  time->tops = 0;
2225  time->ticks = 0;
2226  time->size = 0;
2227  time->sops = 0;
2228  }
2229 }
2230 #endif
2232  HANDLE session,
2233  DWORD version,
2234  DWORD timeout)
2235 {
2238 
2239 #ifdef DEBUG_MOUNT
2240  DbgEn();
2241 #endif
2242  status = nfs41_UpcallCreate(NFS41_UNMOUNT, NULL, session,
2243  INVALID_HANDLE_VALUE, version, NULL, &entry);
2245  if (status) goto out;
2246 
2247  nfs41_UpcallWaitForReply(entry, timeout);
2248  RxFreePool(entry);
2249 out:
2250 #ifdef ENABLE_TIMINGS
2251  print_op_stat("lookup", &lookup, 1);
2252  print_op_stat("open", &open, 1);
2253  print_op_stat("close", &close, 1);
2254  print_op_stat("volume", &volume, 1);
2255  print_op_stat("getattr", &getattr, 1);
2256  print_op_stat("setattr", &setattr, 1);
2257  print_op_stat("getexattr", &getexattr, 1);
2258  print_op_stat("setexattr", &setexattr, 1);
2259  print_op_stat("readdir", &readdir, 1);
2260  print_op_stat("getacl", &getacl, 1);
2261  print_op_stat("setacl", &setacl, 1);
2262  print_op_stat("read", &read, 1);
2263  print_op_stat("write", &write, 1);
2264  print_op_stat("lock", &lock, 1);
2265  print_op_stat("unlock", &unlock, 1);
2266 #endif
2267 #ifdef DEBUG_MOUNT
2268  DbgEx();
2269 #endif
2270  return status;
2271 }
2272 
2274  IN PRX_CONTEXT RxContext,
2275  OUT PBOOLEAN PostToFsp)
2276 {
2278  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
2279  PWCHAR ConnectName = LowIoContext->ParamsFor.IoCtl.pInputBuffer;
2280  ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
2281  HANDLE Handle;
2283  PFILE_OBJECT pFileObject;
2284  BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
2285 
2286 #ifdef DEBUG_MOUNT
2287  DbgEn();
2288 #endif
2289 
2290  if (!Wait) {
2291  //just post right now!
2292  *PostToFsp = TRUE;
2293  DbgP("returning STATUS_PENDING\n");
2294  status = STATUS_PENDING;
2295  goto out;
2296  }
2297 
2298  FileName.Buffer = ConnectName;
2299  FileName.Length = (USHORT) ConnectNameLen - sizeof(WCHAR);
2300  FileName.MaximumLength = (USHORT) ConnectNameLen;
2301 
2302  status = GetConnectionHandle(&FileName, NULL, 0, &Handle);
2303  if (status != STATUS_SUCCESS)
2304  goto out;
2305 
2306  status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode,
2307  (PVOID *)&pFileObject, NULL);
2308  if (NT_SUCCESS(status)) {
2309  PV_NET_ROOT VNetRoot;
2310 
2311  // VNetRoot exists as FOBx in the FsContext2
2312  VNetRoot = (PV_NET_ROOT) pFileObject->FsContext2;
2313  // make sure the node looks right
2314  if (NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT)
2315  {
2316 #ifdef DEBUG_MOUNT
2317  DbgP("Calling RxFinalizeConnection for NetRoot %p from VNetRoot %p\n",
2318  VNetRoot->NetRoot, VNetRoot);
2319 #endif
2320  status = RxFinalizeConnection(VNetRoot->NetRoot, VNetRoot, TRUE);
2321  }
2322  else
2323  status = STATUS_BAD_NETWORK_NAME;
2324 
2325  ObDereferenceObject(pFileObject);
2326  }
2327  ZwClose(Handle);
2328 out:
2329 #ifdef DEBUG_MOUNT
2330  DbgEx();
2331 #endif
2332  return status;
2333 }
2334 
2335 #ifdef __REACTOS__
2337 #else
2339 #endif
2340  IN OUT PRX_CONTEXT RxContext)
2341 {
2343  UCHAR op = RxContext->MajorFunction;
2344  PLOWIO_CONTEXT io_ctx = &RxContext->LowIoContext;
2345  ULONG fsop = io_ctx->ParamsFor.FsCtl.FsControlCode, state;
2346  ULONG in_len = io_ctx->ParamsFor.IoCtl.InputBufferLength;
2347  DWORD *buf = io_ctx->ParamsFor.IoCtl.pInputBuffer;
2348  NFS41GetDeviceExtension(RxContext, DevExt);
2349  DWORD nfs41d_version = 0;
2350 
2351  //DbgEn();
2352 
2353  print_ioctl(0, op);
2354  switch(op) {
2357  break;
2358  case IRP_MJ_DEVICE_CONTROL:
2360  print_fs_ioctl(0, fsop);
2361  switch (fsop) {
2363  nfs41_invalidate_cache(RxContext);
2364  status = STATUS_SUCCESS;
2365  break;
2366  case IOCTL_NFS41_READ:
2367  status = nfs41_upcall(RxContext);
2368  break;
2369  case IOCTL_NFS41_WRITE:
2370  status = nfs41_downcall(RxContext);
2371  break;
2372  case IOCTL_NFS41_ADDCONN:
2373  status = nfs41_CreateConnection(RxContext, &RxContext->PostRequest);
2374  break;
2375  case IOCTL_NFS41_DELCONN:
2376  if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) {
2377  DbgP("device has open handles %d\n",
2378  RxContext->RxDeviceObject->NumberOfActiveFcbs);
2379 #ifdef __REACTOS__
2380  if (RxContext->RxDeviceObject->pRxNetNameTable != NULL)
2381  {
2382 #define DUMP_FCB_TABLE_FROM_NETROOT(N) \
2383 { \
2384  USHORT Bucket2; \
2385  BOOLEAN Release2 = FALSE; \
2386  if (!RxIsFcbTableLockAcquired(&(N)->FcbTable)) \
2387  { \
2388  RxAcquireFcbTableLockExclusive(&(N)->FcbTable, TRUE); \
2389  Release2 = TRUE; \
2390  } \
2391  for (Bucket2 = 0; Bucket2 < (N)->FcbTable.NumberOfBuckets; ++Bucket2) \
2392  { \
2393  PLIST_ENTRY Entry2; \
2394  for (Entry2 = (N)->FcbTable.HashBuckets[Bucket2].Flink; \
2395  Entry2 != &(N)->FcbTable.HashBuckets[Bucket2]; \
2396  Entry2 = Entry2->Flink) \
2397  { \
2398  PFCB Fcb; \
2399  Fcb = CONTAINING_RECORD(Entry2, FCB, FcbTableEntry.HashLinks); \
2400  DbgP("Fcb: %p still has %d references\n", Fcb, Fcb->NodeReferenceCount); \
2401  DbgP("It is for: %wZ\n", &Fcb->FcbTableEntry.Path); \
2402  } \
2403  } \
2404  if (Release2) \
2405  { \
2406  RxReleaseFcbTableLock(&(N)->FcbTable); \
2407  } \
2408 }
2409  USHORT Bucket;
2410  BOOLEAN Release = FALSE;
2411 
2412  if (!RxIsPrefixTableLockAcquired(RxContext->RxDeviceObject->pRxNetNameTable))
2413  {
2414  RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
2415  Release = TRUE;
2416  }
2417 
2418  for (Bucket = 0; Bucket < RxContext->RxDeviceObject->pRxNetNameTable->TableSize; ++Bucket)
2419  {
2421 
2422  for (Entry = RxContext->RxDeviceObject->pRxNetNameTable->HashBuckets[Bucket].Flink;
2423  Entry != &RxContext->RxDeviceObject->pRxNetNameTable->HashBuckets[Bucket];
2424  Entry = Entry->Flink)
2425  {
2426  PVOID Container;
2427 
2428  Container = CONTAINING_RECORD(Entry, RX_PREFIX_ENTRY, HashLinks)->ContainingRecord;
2429  switch (NodeType(Container) & ~RX_SCAVENGER_MASK)
2430  {
2431  case RDBSS_NTC_NETROOT:
2432  {
2433  PNET_ROOT NetRoot;
2434 
2435  NetRoot = Container;
2436  DUMP_FCB_TABLE_FROM_NETROOT(NetRoot);
2437  break;
2438  }
2439 
2440  case RDBSS_NTC_V_NETROOT:
2441  {
2442  PV_NET_ROOT VNetRoot;
2443 
2444  VNetRoot = Container;
2445  if (VNetRoot->NetRoot != NULL)
2446  {
2447  PNET_ROOT NetRoot;
2448 
2449  NetRoot = VNetRoot->NetRoot;
2450  DUMP_FCB_TABLE_FROM_NETROOT(NetRoot);
2451  }
2452  break;
2453  }
2454 
2455  default:
2456  {
2457  DbgP("Other node found: %x\n", NodeType(Container));
2458  break;
2459  }
2460  }
2461  }
2462  }
2463 
2464  if (Release)
2465  {
2466  RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
2467  }
2468 #undef DUMP_FCB_TABLE_FROM_NETROOT
2469  }
2470  else
2471  {
2472  DbgP("RxNetNameTable is NULL for: %p\n", RxContext->RxDeviceObject);
2473  }
2474 #endif
2476  break;
2477  }
2478  status = nfs41_DeleteConnection(RxContext, &RxContext->PostRequest);
2479  break;
2480  case IOCTL_NFS41_GETSTATE:
2482 
2483  if (io_ctx->ParamsFor.IoCtl.OutputBufferLength >= sizeof(ULONG)) {
2484  // map the states to control app's equivalents
2485  print_driver_state(nfs41_start_state);
2486  switch (nfs41_start_state) {
2489  state = RDR_STOPPED;
2490  break;
2492  state = RDR_STARTING;
2493  break;
2495  state = RDR_STARTED;
2496  break;
2497  }
2498  *(ULONG *)io_ctx->ParamsFor.IoCtl.pOutputBuffer = state;
2499  RxContext->InformationToReturn = sizeof(ULONG);
2500  status = STATUS_SUCCESS;
2501  } else
2502  status = STATUS_INVALID_PARAMETER;
2503  break;
2504  case IOCTL_NFS41_START:
2505  print_driver_state(nfs41_start_state);
2506  if (in_len >= sizeof(DWORD)) {
2507  RtlCopyMemory(&nfs41d_version, buf, sizeof(DWORD));
2508  DbgP("NFS41 Daemon sent start request with version %d\n",
2509  nfs41d_version);
2510  DbgP("Currently used NFS41 Daemon version is %d\n",
2511  DevExt->nfs41d_version);
2512  DevExt->nfs41d_version = nfs41d_version;
2513  }
2514  switch(nfs41_start_state) {
2520  //lack of break is intentional
2521  case NFS41_START_DRIVER_START_IN_PROGRESS:
2522  status = RxStartMinirdr(RxContext, &RxContext->PostRequest);
2523  if (status == STATUS_REDIRECTOR_STARTED) {
2524  DbgP("redirector started\n");
2525  status = STATUS_SUCCESS;
2526  } else if (status == STATUS_PENDING &&
2527  RxContext->PostRequest == TRUE) {
2528  DbgP("RxStartMinirdr pending %08lx\n", status);
2530  }
2531  break;
2533  status = STATUS_SUCCESS;
2534  break;
2535  default:
2536  status = STATUS_INVALID_PARAMETER;
2537  }
2538  break;
2539  case IOCTL_NFS41_STOP:
2540  if (nfs41_start_state == NFS41_START_DRIVER_STARTED)
2541  nfs41_shutdown_daemon(DevExt->nfs41d_version);
2542  if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) {
2543  DbgP("device has open handles %d\n",
2544  RxContext->RxDeviceObject->NumberOfActiveFcbs);
2546  break;
2547  }
2548 
2553 
2554  status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
2555  DbgP("RxStopMinirdr status %08lx\n", status);
2556  if (status == STATUS_PENDING && RxContext->PostRequest == TRUE )
2558  break;
2559  default:
2561  };
2562  break;
2563  default:
2565  };
2566 
2567  //DbgEx();
2568  return status;
2569 }
2570 
2571 #ifndef __REACTOS__
2573  PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
2574 {
2575 #else
2577  PVOID pContext)
2578 {
2579  PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext = pContext;
2580 #endif
2582  PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
2583  PMRX_SRV_CALL pSrvCall;
2584  PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure =
2586  PNFS41_SERVER_ENTRY pServerEntry = NULL;
2587 
2588 #ifdef DEBUG_MOUNT
2589  DbgEn();
2590 #endif
2591 
2592  pSrvCall = SrvCalldownStructure->SrvCall;
2593 
2594  ASSERT( pSrvCall );
2595  ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
2596  print_srv_call(0, pSrvCall);
2597 
2598  // validate the server name with the test name of 'pnfs'
2599 #ifdef DEBUG_MOUNT
2600  DbgP("SrvCall: Connection Name Length: %d %wZ\n",
2601  pSrvCall->pSrvCallName->Length, pSrvCall->pSrvCallName);
2602 #endif
2603 
2604  if (pSrvCall->pSrvCallName->Length > SERVER_NAME_BUFFER_SIZE) {
2605  print_error("Server name '%wZ' too long for server entry (max %u)\n",
2607  status = STATUS_NAME_TOO_LONG;
2608  goto out;
2609  }
2610 
2611  /* Let's create our own representation of the server */
2614  if (pServerEntry == NULL) {
2616  goto out;
2617  }
2618  RtlZeroMemory(pServerEntry, sizeof(NFS41_SERVER_ENTRY));
2619 
2620  pServerEntry->Name.Buffer = pServerEntry->NameBuffer;
2621  pServerEntry->Name.Length = pSrvCall->pSrvCallName->Length;
2622  pServerEntry->Name.MaximumLength = SERVER_NAME_BUFFER_SIZE;
2623  RtlCopyMemory(pServerEntry->Name.Buffer, pSrvCall->pSrvCallName->Buffer,
2624  pServerEntry->Name.Length);
2625 
2626  pCallbackContext->RecommunicateContext = pServerEntry;
2627 #ifdef __REACTOS__
2628  InterlockedExchangePointer((void * volatile *)&pServerEntry->pRdbssSrvCall, pSrvCall);
2629 #else
2630  InterlockedExchangePointer(&pServerEntry->pRdbssSrvCall, pSrvCall);
2631 #endif
2632 
2633 out:
2634  SCCBC->Status = status;
2635  SrvCalldownStructure->CallBack(SCCBC);
2636 
2637 #ifdef DEBUG_MOUNT
2638  DbgEx();
2639 #endif
2640  return status;
2641 }
2642 
2643 #ifdef __REACTOS__
2644 VOID NTAPI _nfs41_CreateSrvCall_v(
2645  PVOID pCallbackContext)
2646 {
2647  _nfs41_CreateSrvCall(pCallbackContext);
2648 }
2649 #endif
2650 
2651 #ifdef __REACTOS__
2653 #else
2655 #endif
2656  PMRX_SRV_CALL pSrvCall,
2657  PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
2658 {
2659  NTSTATUS status;
2660 
2661  ASSERT( pSrvCall );
2662  ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
2663 
2665  DbgP("executing with RDBSS context\n");
2666  status = _nfs41_CreateSrvCall(pCallbackContext);
2667  } else {
2668  status = RxDispatchToWorkerThread(nfs41_dev, DelayedWorkQueue,
2669 #ifdef __REACTOS__
2670  _nfs41_CreateSrvCall_v, pCallbackContext);
2671 #else
2672  _nfs41_CreateSrvCall, pCallbackContext);
2673 #endif
2674  if (status != STATUS_SUCCESS) {
2675  print_error("RxDispatchToWorkerThread returned status %08lx\n",
2676  status);
2677  pCallbackContext->Status = status;
2678  pCallbackContext->SrvCalldownStructure->CallBack(pCallbackContext);
2679  status = STATUS_PENDING;
2680  }
2681  }
2682  /* RDBSS expects MRxCreateSrvCall to return STATUS_PENDING */
2683  if (status == STATUS_SUCCESS)
2684  status = STATUS_PENDING;
2685 
2686  return status;
2687 }
2688 
2689 #ifdef __REACTOS__
2691 #else
2693 #endif
2694  IN OUT PMRX_SRV_CALL pSrvCall,
2695  IN BOOLEAN ThisMinirdrIsTheWinner,
2696  IN OUT PVOID pSrvCallContext)
2697 {
2699  PNFS41_SERVER_ENTRY pServerEntry;
2700 
2701  pServerEntry = (PNFS41_SERVER_ENTRY)pSrvCallContext;
2702 
2703  if (!ThisMinirdrIsTheWinner) {
2704  ASSERT(1);
2705  goto out;
2706  }
2707 
2708  pSrvCall->Context = pServerEntry;
2709 out:
2710  return status;
2711 }
2712 
2714  DWORD status)
2715 {
2716  switch (status) {
2717  case NO_ERROR: return STATUS_SUCCESS;
2722  default:
2723  print_error("failed to map windows error %d to NTSTATUS; "
2724  "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status);
2726  }
2727 }
2728 
2730  PNFS41_MOUNT_CONFIG config,
2731  DWORD sec_flavor,
2732  PHANDLE session,
2733  DWORD *version,
2735 {
2738 
2739 #ifdef DEBUG_MOUNT
2740  DbgEn();
2741  DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
2742  &config->SrvName, &config->MntPt, sec_flavor);
2743 #endif
2744  status = nfs41_UpcallCreate(NFS41_MOUNT, NULL, *session,
2745  INVALID_HANDLE_VALUE, *version, &config->MntPt, &entry);
2746  if (status) goto out;
2747 
2748  entry->u.Mount.srv_name = &config->SrvName;
2749  entry->u.Mount.root = &config->MntPt;
2750  entry->u.Mount.rsize = config->ReadSize;
2751  entry->u.Mount.wsize = config->WriteSize;
2752  entry->u.Mount.sec_flavor = sec_flavor;
2753  entry->u.Mount.FsAttrs = FsAttrs;
2754 
2755  status = nfs41_UpcallWaitForReply(entry, config->timeout);
2757  if (status) goto out;
2758  *session = entry->session;
2759  if (entry->u.Mount.lease_time > config->timeout)
2760  config->timeout = entry->u.Mount.lease_time;
2761 
2762  /* map windows ERRORs to NTSTATUS */
2763  status = map_mount_errors(entry->status);
2764  if (status == STATUS_SUCCESS)
2765  *version = entry->version;
2766  RxFreePool(entry);
2767 out:
2768 #ifdef DEBUG_MOUNT
2769  DbgEx();
2770 #endif
2771  return status;
2772 }
2773 
2774 /* TODO: move mount config stuff to another file -cbodley */
2775 
2777  OUT PNFS41_MOUNT_CONFIG Config)
2778 {
2779  RtlZeroMemory(Config, sizeof(NFS41_MOUNT_CONFIG));
2780 
2781  Config->ReadSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
2782  Config->WriteSize = MOUNT_CONFIG_RW_SIZE_DEFAULT;
2783  Config->ReadOnly = FALSE;
2784  Config->write_thru = FALSE;
2785  Config->nocache = FALSE;
2786  Config->SrvName.Length = 0;
2787  Config->SrvName.MaximumLength = SERVER_NAME_BUFFER_SIZE;
2788  Config->SrvName.Buffer = Config->srv_buffer;
2789  Config->MntPt.Length = 0;
2790  Config->MntPt.MaximumLength = MAX_PATH;
2791  Config->MntPt.Buffer = Config->mntpt_buffer;
2792  Config->SecFlavor.Length = 0;
2793  Config->SecFlavor.MaximumLength = MAX_SEC_FLAVOR_LEN;
2794  Config->SecFlavor.Buffer = Config->sec_flavor;
2795  RtlCopyUnicodeString(&Config->SecFlavor, &AUTH_SYS_NAME);
2796  Config->timeout = UPCALL_TIMEOUT_DEFAULT;
2797 }
2798 
2801  IN PUNICODE_STRING usValue,
2802  OUT PBOOLEAN Value)
2803 {
2805 
2806  /* if no value is specified, assume TRUE
2807  * if a value is specified, it must be a '1' */
2808  if (Option->EaValueLength == 0 || *usValue->Buffer == L'1')
2809  *Value = TRUE;
2810  else
2811  *Value = FALSE;
2812 
2813  DbgP(" '%ls' -> '%wZ' -> %u\n",
2814  (LPWSTR)Option->EaName, usValue, *Value);
2815  return status;
2816 }
2817 
2820  IN PUNICODE_STRING usValue,
2821  OUT PDWORD Value,
2822  IN DWORD Minimum,
2823  IN DWORD Maximum)
2824 {
2826  LPWSTR Name = (LPWSTR)Option->EaName;
2827 
2828  if (Option->EaValueLength) {
2829  status = RtlUnicodeStringToInteger(usValue, 0, Value);
2830  if (status == STATUS_SUCCESS) {
2831 #ifdef IMPOSE_MINMAX_RWSIZES
2832  if (*Value < Minimum)
2833  *Value = Minimum;
2834  if (*Value > Maximum)
2835  *Value = Maximum;
2836  DbgP(" '%ls' -> '%wZ' -> %lu\n", Name, usValue, *Value);
2837 #endif
2838  }
2839  else
2840  print_error("Failed to convert %s='%wZ' to unsigned long.\n",
2841  Name, usValue);
2842  }
2843 
2844  return status;
2845 }
2846 
2849  IN ULONG EaLength,
2850  IN OUT PNFS41_MOUNT_CONFIG Config)
2851 {
2854  LPWSTR Name;
2855  size_t NameLen;
2856  UNICODE_STRING usValue;
2857  Option = EaBuffer;
2858  while (status == STATUS_SUCCESS) {
2859  Name = (LPWSTR)Option->EaName;
2860  NameLen = Option->EaNameLength/sizeof(WCHAR);
2861 
2862  usValue.Length = usValue.MaximumLength = Option->EaValueLength;
2863  usValue.Buffer = (PWCH)(Option->EaName +
2864  Option->EaNameLength + sizeof(WCHAR));
2865 
2866  if (wcsncmp(L"ro", Name, NameLen) == 0) {
2867  status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2868  &Config->ReadOnly);
2869  }
2870  else if (wcsncmp(L"writethru", Name, NameLen) == 0) {
2871  status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2872  &Config->write_thru);
2873  }
2874  else if (wcsncmp(L"nocache", Name, NameLen) == 0) {
2875  status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2876  &Config->nocache);
2877  }
2878  else if (wcsncmp(L"timeout", Name, NameLen) == 0) {
2879  status = nfs41_MountConfig_ParseDword(Option, &usValue,
2880  &Config->timeout, UPCALL_TIMEOUT_DEFAULT,
2882  }
2883  else if (wcsncmp(L"rsize", Name, NameLen) == 0) {
2884  status = nfs41_MountConfig_ParseDword(Option, &usValue,
2885  &Config->ReadSize, MOUNT_CONFIG_RW_SIZE_MIN,
2887  }
2888  else if (wcsncmp(L"wsize", Name, NameLen) == 0) {
2889  status = nfs41_MountConfig_ParseDword(Option, &usValue,
2890  &Config->WriteSize, MOUNT_CONFIG_RW_SIZE_MIN,
2892  }
2893  else if (wcsncmp(L"srvname", Name, NameLen) == 0) {
2894  if (usValue.Length > Config->SrvName.MaximumLength)
2895  status = STATUS_NAME_TOO_LONG;
2896  else
2897  RtlCopyUnicodeString(&Config->SrvName, &usValue);
2898  }
2899  else if (wcsncmp(L"mntpt", Name, NameLen) == 0) {
2900  if (usValue.Length > Config->MntPt.MaximumLength)
2901  status = STATUS_NAME_TOO_LONG;
2902  else
2903  RtlCopyUnicodeString(&Config->MntPt, &usValue);
2904  }
2905  else if (wcsncmp(L"sec", Name, NameLen) == 0) {
2906  if (usValue.Length > Config->SecFlavor.MaximumLength)
2907  status = STATUS_NAME_TOO_LONG;
2908  else
2909  RtlCopyUnicodeString(&Config->SecFlavor, &usValue);
2910  }
2911  else {
2912  status = STATUS_INVALID_PARAMETER;
2913  print_error("Unrecognized option '%ls' -> '%wZ'\n",
2914  Name, usValue);
2915  }
2916 
2917  if (Option->NextEntryOffset == 0)
2918  break;
2919 
2920  Option = (PFILE_FULL_EA_INFORMATION)
2921  ((PBYTE)Option + Option->NextEntryOffset);
2922  }
2923 
2924  return status;
2925 }
2926 
2928  IN PUNICODE_STRING SrvCallName,
2930 {
2932 
2933  if (NetRootName->Length == SrvCallName->Length + NfsPrefix.Length) {
2934  const UNICODE_STRING NetRootPrefix = {
2935  NfsPrefix.Length,
2936  NetRootName->MaximumLength - SrvCallName->Length,
2937  &NetRootName->Buffer[SrvCallName->Length/2]
2938  };
2939  if (RtlCompareUnicodeString(&NetRootPrefix, &NfsPrefix, FALSE) == 0)
2940  status = STATUS_SUCCESS;
2941  }
2942  return status;
2943 }
2944 
2946  IN PUNICODE_STRING sec_flavor_name,
2948 {
2949  if (RtlCompareUnicodeString(sec_flavor_name, &AUTH_SYS_NAME, FALSE) == 0)
2950  *sec_flavor = RPCSEC_AUTH_SYS;
2951  else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5_NAME, FALSE) == 0)
2952  *sec_flavor = RPCSEC_AUTHGSS_KRB5;
2953  else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5I_NAME, FALSE) == 0)
2954  *sec_flavor = RPCSEC_AUTHGSS_KRB5I;
2955  else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5P_NAME, FALSE) == 0)
2956  *sec_flavor = RPCSEC_AUTHGSS_KRB5P;
2957  else return STATUS_INVALID_PARAMETER;
2958  return STATUS_SUCCESS;
2959 }
2960 
2962  PLUID id)
2963 {
2965  SECURITY_SUBJECT_CONTEXT sec_ctx;
2967  SECURITY_CLIENT_CONTEXT clnt_sec_ctx;
2968 
2969  SeCaptureSubjectContext(&sec_ctx);
2972  sec_qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
2973  sec_qos.EffectiveOnly = 0;
2974  status = SeCreateClientSecurityFromSubjectContext(&sec_ctx, &sec_qos, 1,
2975  &clnt_sec_ctx);
2976  if (status) {
2977  print_error("nfs41_GetLUID: SeCreateClientSecurityFromSubjectContext "
2978  "failed %x\n", status);
2979  goto release_sec_ctx;
2980  }
2981  status = SeQueryAuthenticationIdToken(clnt_sec_ctx.ClientToken, id);
2982  if (status) {
2983  print_error("SeQueryAuthenticationIdToken failed %x\n", status);
2984  goto release_clnt_sec_ctx;
2985  }
2986 release_clnt_sec_ctx:
2987  SeDeleteClientSecurity(&clnt_sec_ctx);
2988 release_sec_ctx:
2989  SeReleaseSubjectContext(&sec_ctx);
2990 
2991  return status;
2992 }
2993 
2996  OUT PSECURITY_CLIENT_CONTEXT out_ctx)
2997 {
2998  NTSTATUS status;
3001 
3004  sec_qos.ImpersonationLevel = level;
3005  sec_qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
3006  sec_qos.EffectiveOnly = 0;
3007  status = SeCreateClientSecurityFromSubjectContext(&ctx, &sec_qos, 1, out_ctx);
3008  if (status != STATUS_SUCCESS) {
3009  print_error("SeCreateClientSecurityFromSubjectContext "
3010  "failed with %x\n", status);
3011  }
3012 #ifdef DEBUG_MOUNT
3013  DbgP("Created client security token %p\n", out_ctx->ClientToken);
3014 #endif
3016 
3017  return status;
3018 }
3019 
3020 #ifdef __REACTOS__
3022 #else
3024 #endif
3025  IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
3026 {
3030  pCreateNetRootContext->pVNetRoot;
3031  __notnull PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
3032  __notnull PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
3033  __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
3034  NFS41GetVNetRootExtension(pVNetRoot);
3035  __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
3036  NFS41GetNetRootExtension(pNetRoot);
3037  NFS41GetDeviceExtension(pCreateNetRootContext->RxContext,DevExt);
3038  DWORD nfs41d_version = DevExt->nfs41d_version;
3039  nfs41_mount_entry *existing_mount = NULL;
3040  LUID luid;
3041  BOOLEAN found_existing_mount = FALSE, found_matching_flavor = FALSE;
3042 
3043  ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
3044  (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
3045 
3046 #ifdef DEBUG_MOUNT
3047  DbgEn();
3048  print_srv_call(0, pSrvCall);
3049  print_net_root(0, pNetRoot);
3050  print_v_net_root(0, pVNetRoot);
3051 
3052  DbgP("pVNetRoot=%p pNetRoot=%p pSrvCall=%p\n", pVNetRoot, pNetRoot, pSrvCall);
3053  DbgP("pNetRoot=%wZ Type=%d pSrvCallName=%wZ VirtualNetRootStatus=0x%x "
3054  "NetRootStatus=0x%x\n", pNetRoot->pNetRootName,
3055  pNetRoot->Type, pSrvCall->pSrvCallName,
3056  pCreateNetRootContext->VirtualNetRootStatus,
3057  pCreateNetRootContext->NetRootStatus);
3058 #endif
3059 
3060  if (pNetRoot->Type != NET_ROOT_DISK && pNetRoot->Type != NET_ROOT_WILD) {
3061  print_error("nfs41_CreateVNetRoot: Unsupported NetRoot Type %u\n",
3062  pNetRoot->Type);
3063  status = STATUS_NOT_SUPPORTED;
3064  goto out;
3065  }
3066 
3067  pVNetRootContext->session = INVALID_HANDLE_VALUE;
3068 
3069  /* In order to cooperate with other network providers, we must
3070  * only claim paths of the form '\\server\nfs4\path' */
3071  status = has_nfs_prefix(pSrvCall->pSrvCallName, pNetRoot->pNetRootName);
3072  if (status) {
3073  print_error("nfs41_CreateVNetRoot: NetRootName %wZ doesn't match "
3074  "'\\nfs4'!\n", pNetRoot->pNetRootName);
3075  goto out;
3076  }
3077  pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
3078  pNetRoot->DeviceType = FILE_DEVICE_DISK;
3079 
3082  if (Config == NULL) {
3084  goto out;
3085  }
3087 
3088  if (pCreateNetRootContext->RxContext->Create.EaLength) {
3089  /* parse the extended attributes for mount options */
3091  pCreateNetRootContext->RxContext->Create.EaBuffer,
3092  pCreateNetRootContext->RxContext->Create.EaLength,
3093  Config);
3094  if (status != STATUS_SUCCESS)
3095  goto out_free;
3096  pVNetRootContext->read_only = Config->ReadOnly;
3097  pVNetRootContext->write_thru = Config->write_thru;
3098  pVNetRootContext->nocache = Config->nocache;
3099  } else {
3100  /* use the SRV_CALL name (without leading \) as the hostname */
3101  Config->SrvName.Buffer = pSrvCall->pSrvCallName->Buffer + 1;
3102  Config->SrvName.Length =
3103  pSrvCall->pSrvCallName->Length - sizeof(WCHAR);
3104  Config->SrvName.MaximumLength =
3105  pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR);
3106  }
3107  pVNetRootContext->MountPathLen = Config->MntPt.Length;
3108  pVNetRootContext->timeout = Config->timeout;
3109 
3110  status = map_sec_flavor(&Config->SecFlavor, &pVNetRootContext->sec_flavor);
3111  if (status != STATUS_SUCCESS) {
3112  DbgP("Invalid rpcsec security flavor %wZ\n", &Config->SecFlavor);
3113  goto out_free;
3114  }
3115 
3116  status = nfs41_GetLUID(&luid);
3117  if (status)
3118  goto out_free;
3119 
3120  if (!pNetRootContext->mounts_init) {
3121 #ifdef DEBUG_MOUNT
3122  DbgP("Initializing mount array\n");
3123 #endif
3124  ExInitializeFastMutex(&pNetRootContext->mountLock);
3125  InitializeListHead(&pNetRootContext->mounts.head);
3126  pNetRootContext->mounts_init = TRUE;
3127  } else {
3128  PLIST_ENTRY pEntry;
3129 
3130  ExAcquireFastMutex(&pNetRootContext->mountLock);
3131  pEntry = &pNetRootContext->mounts.head;
3132  pEntry = pEntry->Flink;
3133  while (pEntry != NULL) {
3134  existing_mount = (nfs41_mount_entry *)CONTAINING_RECORD(pEntry,
3136 #ifdef DEBUG_MOUNT
3137  DbgP("comparing %x.%x with %x.%x\n", luid.HighPart, luid.LowPart,
3138  existing_mount->login_id.HighPart, existing_mount->login_id.LowPart);
3139 #endif
3140  if (RtlEqualLuid(&luid, &existing_mount->login_id)) {
3141 #ifdef DEBUG_MOUNT
3142  DbgP("Found a matching LUID entry\n");
3143 #endif
3144  found_existing_mount = TRUE;
3145  switch(pVNetRootContext->sec_flavor) {
3146  case RPCSEC_AUTH_SYS:
3147  if (existing_mount->authsys_session != INVALID_HANDLE_VALUE)
3148  pVNetRootContext->session =
3149  existing_mount->authsys_session;
3150  break;
3151  case RPCSEC_AUTHGSS_KRB5:
3152  if (existing_mount->gssi_session != INVALID_HANDLE_VALUE)
3153  pVNetRootContext->session = existing_mount->gss_session;
3154  break;
3155  case RPCSEC_AUTHGSS_KRB5I:
3156  if (existing_mount->gss_session != INVALID_HANDLE_VALUE)
3157  pVNetRootContext->session = existing_mount->gssi_session;
3158  break;
3159  case RPCSEC_AUTHGSS_KRB5P:
3160  if (existing_mount->gssp_session != INVALID_HANDLE_VALUE)
3161  pVNetRootContext->session = existing_mount->gssp_session;
3162  break;
3163  }
3164  if (pVNetRootContext->session &&
3165  pVNetRootContext->session != INVALID_HANDLE_VALUE)
3166  found_matching_flavor = 1;
3167  break;
3168  }
3169  if (pEntry->Flink == &pNetRootContext->mounts.head)
3170  break;
3171  pEntry = pEntry->Flink;
3172  }
3173  ExReleaseFastMutex(&pNetRootContext->mountLock);
3174 #ifdef DEBUG_MOUNT
3175  if (!found_matching_flavor)
3176  DbgP("Didn't find matching security flavor\n");
3177 #endif
3178  }
3179 
3180  /* send the mount upcall */
3181  status = nfs41_mount(Config, pVNetRootContext->sec_flavor,
3182  &pVNetRootContext->session, &nfs41d_version,
3183  &pVNetRootContext->FsAttrs);
3184  if (status != STATUS_SUCCESS) {
3185  BOOLEAN MountsEmpty;
3186  nfs41_IsListEmpty(pNetRootContext->mountLock,
3187  pNetRootContext->mounts, MountsEmpty);
3188  if (!found_existing_mount && MountsEmpty)
3189  pNetRootContext->mounts_init = FALSE;
3190  pVNetRootContext->session = INVALID_HANDLE_VALUE;
3191  goto out_free;
3192  }
3193  pVNetRootContext->timeout = Config->timeout;
3194 
3195  if (!found_existing_mount) {
3196  /* create a new mount entry and add it to the list */
3200  if (entry == NULL) {
3202  goto out_free;
3203  }
3204  entry->authsys_session = entry->gss_session =
3206  switch (pVNetRootContext->sec_flavor) {
3207  case RPCSEC_AUTH_SYS:
3208  entry->authsys_session = pVNetRootContext->session; break;
3209  case RPCSEC_AUTHGSS_KRB5:
3210  entry->gss_session = pVNetRootContext->session; break;
3211  case RPCSEC_AUTHGSS_KRB5I:
3212  entry->gssi_session = pVNetRootContext->session; break;
3213  case RPCSEC_AUTHGSS_KRB5P:
3214  entry->gssp_session = pVNetRootContext->session; break;
3215  }
3216  RtlCopyLuid(&entry->login_id, &luid);
3217  nfs41_AddEntry(pNetRootContext->mountLock,
3218  pNetRootContext->mounts, entry);
3219  } else if (!found_matching_flavor) {
3220  ASSERT(existing_mount != NULL);
3221  /* modify existing mount entry */
3222 #ifdef DEBUG_MOUNT
3223  DbgP("Using existing %d flavor session 0x%x\n",
3224  pVNetRootContext->sec_flavor);
3225 #endif
3226  switch (pVNetRootContext->sec_flavor) {
3227  case RPCSEC_AUTH_SYS:
3228  existing_mount->authsys_session = pVNetRootContext->session; break;
3229  case RPCSEC_AUTHGSS_KRB5:
3230  existing_mount->gss_session = pVNetRootContext->session; break;
3231  case RPCSEC_AUTHGSS_KRB5I:
3232  existing_mount->gssi_session = pVNetRootContext->session; break;
3233  case RPCSEC_AUTHGSS_KRB5P:
3234  existing_mount->gssp_session = pVNetRootContext->session; break;
3235  }
3236  }
3237  pNetRootContext->nfs41d_version = nfs41d_version;
3238 #ifdef DEBUG_MOUNT
3239  DbgP("Saving new session 0x%x\n", pVNetRootContext->session);
3240 #endif
3241 #ifdef STORE_MOUNT_SEC_CONTEXT
3243  &pVNetRootContext->mount_sec_ctx);
3244 #endif
3245 
3246 out_free:
3247  RxFreePool(Config);
3248 out:
3249  pCreateNetRootContext->VirtualNetRootStatus = status;
3250  if (pNetRoot->Context == NULL)
3251  pCreateNetRootContext->NetRootStatus = status;
3252  pCreateNetRootContext->Callback(pCreateNetRootContext);
3253 
3254  /* RDBSS expects that MRxCreateVNetRoot returns STATUS_PENDING
3255  * on success or failure */
3256  status = STATUS_PENDING;
3257 #ifdef DEBUG_MOUNT
3258  DbgEx();
3259 #endif
3260  return status;
3261 }
3262 
3263 #ifdef __REACTOS__
3265 #else
3267 #endif
3268  IN PUNICODE_STRING FilePathName,
3272 {
3273  ULONG length = FilePathName->Length;
3274  PWCH w = FilePathName->Buffer;
3275  PWCH wlimit = (PWCH)(((PCHAR)w)+length);
3276  PWCH wlow;
3277 
3278  w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
3279  NetRootName->Buffer = wlow = w;
3280  /* parse the entire path into NetRootName */
3281 #if USE_ENTIRE_PATH
3282  w = wlimit;
3283 #else
3284  for (;;) {
3285  if (w >= wlimit)
3286  break;
3287  if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow))
3288  break;
3289  w++;
3290  }
3291 #endif
3292  NetRootName->Length = NetRootName->MaximumLength
3293  = (USHORT)((PCHAR)w - (PCHAR)wlow);
3294 #ifdef DEBUG_MOUNT
3295  DbgP("In: pSrvCall %p PathName=%wZ SrvCallName=%wZ Out: NetRootName=%wZ\n",
3296  SrvCall, FilePathName, SrvCall->pSrvCallName, NetRootName);
3297 #endif
3298  return;
3299 
3300 }
3301 
3302 #ifdef __REACTOS__
3304 #else
3306 #endif
3307  PMRX_SRV_CALL pSrvCall,
3308  BOOLEAN Force)
3309 {
3311  PNFS41_SERVER_ENTRY pServerEntry = (PNFS41_SERVER_ENTRY)(pSrvCall->Context);
3312 
3313 #ifdef DEBUG_MOUNT
3314  DbgEn();
3315 #endif
3316  print_srv_call(0, pSrvCall);
3317 
3318  if (pSrvCall->Context == NULL)
3319  goto out;
3320 
3321 #ifndef __REACTOS__
3323  NULL, pSrvCall);
3324 #else
3325  InterlockedCompareExchangePointer((void * volatile *)&pServerEntry->pRdbssSrvCall,
3326  NULL, pSrvCall);
3327 #endif
3328  RxFreePool(pServerEntry);
3329 
3330  pSrvCall->Context = NULL;
3331 out:
3332 #ifdef DEBUG_MOUNT
3333  DbgEx();
3334 #endif
3335  return status;
3336 }
3337 
3338 #ifdef __REACTOS__
3340 #else
3342 #endif
3343  IN OUT PMRX_NET_ROOT pNetRoot,
3344  IN PBOOLEAN ForceDisconnect)
3345 {
3347  PNFS41_NETROOT_EXTENSION pNetRootContext =
3350  nfs41_mount_entry *mount_tmp;
3351 
3352 #ifdef DEBUG_MOUNT
3353  DbgEn();
3354  print_net_root(1, pNetRoot);
3355 #endif
3356 
3357  if (pNetRoot->Type != NET_ROOT_DISK && pNetRoot->Type != NET_ROOT_WILD) {
3358  status = STATUS_NOT_SUPPORTED;
3359  goto out;
3360  }
3361 
3362  if (pNetRootContext == NULL || !pNetRootContext->mounts_init) {
3363  print_error("nfs41_FinalizeNetRoot: No valid session established\n");
3364  goto out;
3365  }
3366 
3367  if (pNetRoot->NumberOfFcbs > 0 || pNetRoot->NumberOfSrvOpens > 0) {
3368  print_error("%d open Fcbs %d open SrvOpens\n", pNetRoot->NumberOfFcbs,
3369  pNetRoot->NumberOfSrvOpens);
3370  goto out;
3371  }
3372 
3373  do {
3374  nfs41_GetFirstMountEntry(pNetRootContext->mountLock,
3375  pNetRootContext->mounts, mount_tmp);
3376  if (mount_tmp == NULL)
3377  break;
3378 #ifdef DEBUG_MOUNT
3379  DbgP("Removing entry luid %x.%x from mount list\n",
3380  mount_tmp->login_id.HighPart, mount_tmp->login_id.LowPart);
3381 #endif
3382  if (mount_tmp->authsys_session != INVALID_HANDLE_VALUE) {
3383  status = nfs41_unmount(mount_tmp->authsys_session,
3384  pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3385  if (status)
3386  print_error("nfs41_unmount AUTH_SYS failed with %d\n", status);
3387  }
3388  if (mount_tmp->gss_session != INVALID_HANDLE_VALUE) {
3389  status = nfs41_unmount(mount_tmp->gss_session,
3390  pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3391  if (status)
3392  print_error("nfs41_unmount RPCSEC_GSS_KRB5 failed with %d\n",
3393  status);
3394  }
3395  if (mount_tmp->gssi_session != INVALID_HANDLE_VALUE) {
3396  status = nfs41_unmount(mount_tmp->gssi_session,
3397  pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3398  if (status)
3399  print_error("nfs41_unmount RPCSEC_GSS_KRB5I failed with %d\n",
3400  status);
3401  }
3402  if (mount_tmp->gssp_session != INVALID_HANDLE_VALUE) {
3403  status = nfs41_unmount(mount_tmp->gssp_session,
3404  pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3405  if (status)
3406  print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n",
3407  status);
3408  }
3409  nfs41_RemoveEntry(pNetRootContext->mountLock, mount_tmp);
3410  RxFreePool(mount_tmp);
3411  } while (1);
3412  /* ignore any errors from unmount */
3413  status = STATUS_SUCCESS;
3414 
3415  // check if there is anything waiting in the upcall or downcall queue
3416  do {
3417  nfs41_GetFirstEntry(upcallLock, upcall, tmp);
3418  if (tmp != NULL) {
3419  DbgP("Removing entry from upcall list\n");
3422  KeSetEvent(&tmp->cond, 0, FALSE);
3423  } else
3424  break;
3425  } while (1);
3426 
3427  do {
3428  nfs41_GetFirstEntry(downcallLock, downcall, tmp);
3429  if (tmp != NULL) {
3430  DbgP("Removing entry from downcall list\n");
3433  KeSetEvent(&tmp->cond, 0, FALSE);
3434  } else
3435  break;
3436  } while (1);
3437 out:
3438 #ifdef DEBUG_MOUNT
3439  DbgEx();
3440 #endif
3441  return status;
3442 }
3443 
3444 #ifdef __REACTOS__
3446 #else
3448 #endif
3449  IN OUT PMRX_V_NET_ROOT pVNetRoot,
3450  IN PBOOLEAN ForceDisconnect)
3451 {
3453  PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
3454  NFS41GetVNetRootExtension(pVNetRoot);
3455 #ifdef DEBUG_MOUNT
3456  DbgEn();
3457  print_v_net_root(1, pVNetRoot);
3458 #endif
3459  if (pVNetRoot->pNetRoot->Type != NET_ROOT_DISK &&
3460  pVNetRoot->pNetRoot->Type != NET_ROOT_WILD)
3461  status = STATUS_NOT_SUPPORTED;
3462 #ifdef STORE_MOUNT_SEC_CONTEXT
3463  else if (pVNetRootContext->session != INVALID_HANDLE_VALUE) {
3464 #ifdef DEBUG_MOUNT
3465  DbgP("nfs41_FinalizeVNetRoot: deleting security context: %p\n",
3466  pVNetRootContext->mount_sec_ctx.ClientToken);
3467 #endif
3468  SeDeleteClientSecurity(&pVNetRootContext->mount_sec_ctx);
3469  }
3470 #endif
3471 #ifdef DEBUG_MOUNT
3472  DbgEx();
3473 #endif
3474  return status;
3475 }
3476 
3478  ACCESS_MASK mask)
3479 {
3481  return TRUE;
3482  return FALSE;
3483 }
3484 
3486  ULONG disposition)
3487 {
3488  if (disposition == FILE_CREATE || disposition == FILE_OPEN_IF ||
3489  disposition == FILE_OVERWRITE_IF || disposition == FILE_SUPERSEDE)
3490  return TRUE;
3491  return FALSE;
3492 }
3493 
3496  PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext)
3497 {
3498  PFILE_FS_ATTRIBUTE_INFORMATION attrs = &pVNetRootContext->FsAttrs;
3499  LONG len = attrs->MaximumComponentNameLength, count = 1, i;
3500  PWCH p = name->Buffer;
3501  for (i = 0; i < name->Length / 2; i++) {
3502  if (p[0] == L'\\') count = 1;
3503  else {
3504  if (p[0] == L'\0') return FALSE;
3505  if (count > len) return TRUE;
3506  count++;
3507  }
3508  p++;
3509  }
3510  return FALSE;
3511 }
3512 
3515 {
3516  LONG i;
3517  PWCH p = name->Buffer;
3518  for (i = 0; i < name->Length / 2; i++) {
3519  if (p[0] == L':') return TRUE;
3520  else if (p[0] == L'\0') return FALSE;
3521  p++;
3522  }
3523  return FALSE;
3524 }
3525 
3527 {
3528  /* from ms-fsa page 52 */
3529  if ((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
3530  !(params->DesiredAccess & DELETE))
3531  return FALSE;
3532  if ((params->CreateOptions & FILE_DIRECTORY_FILE) &&
3533  (params->Disposition == FILE_SUPERSEDE ||
3534  params->Disposition == FILE_OVERWRITE ||
3535  params->Disposition == FILE_OVERWRITE_IF))
3536  return FALSE;
3538  (params->DesiredAccess & FILE_APPEND_DATA) &&
3539  !(params->DesiredAccess & FILE_WRITE_DATA))
3540  return FALSE;
3541  /* from ms-fsa 3.1.5.1.1 page 56 */
3542  if ((params->CreateOptions & FILE_DIRECTORY_FILE) &&
3544  return FALSE;
3545  return TRUE;
3546 }
3547 
3549  DWORD status,
3550  USHORT len)
3551 {
3552  switch (status) {
3553  case NO_ERROR: return STATUS_SUCCESS;
3554  case ERROR_ACCESS_DENIED:
3555  if (len > 0) return STATUS_ACCESS_DENIED;
3556  else return STATUS_SUCCESS;
3567  case ERROR_REPARSE: return STATUS_REPARSE;
3571  default:
3572  print_error("[ERROR] nfs41_Create: upcall returned %d returning "
3573  "STATUS_INSUFFICIENT_RESOURCES\n", status);
3575  }
3576 }
3577 
3579  DWORD disposition,
3580  DWORD errno)
3581 {
3582  switch(disposition) {
3583  case FILE_SUPERSEDE:
3584  if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED;
3585  else return FILE_SUPERSEDED;
3586  case FILE_CREATE: return FILE_CREATED;
3587  case FILE_OPEN: return FILE_OPENED;
3588  case FILE_OPEN_IF:
3589  if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED;
3590  else return FILE_OPENED;
3591  case FILE_OVERWRITE: return FILE_OVERWRITTEN;
3592  case FILE_OVERWRITE_IF:
3593  if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED;
3594  else return FILE_OVERWRITTEN;
3595  default:
3596  print_error("unknown disposition %d\n", disposition);
3597  return FILE_OPENED;
3598  }
3599 }
3600 
3603  IN ULONG disposition)
3604 {
3605  /* don't pass cygwin EAs */
3606  if (AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength)
3607  || AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength)
3608  || AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength))
3609  return FALSE;
3610  /* only set EAs on file creation */
3611  return disposition == FILE_SUPERSEDE || disposition == FILE_CREATE
3612  || disposition == FILE_OPEN_IF || disposition == FILE_OVERWRITE
3613  || disposition == FILE_OVERWRITE_IF;
3614 }
3615 
3617  IN PRX_CONTEXT RxContext)
3618 {
3620  PNT_CREATE_PARAMETERS params = &RxContext->Create.NtCreateParameters;
3621  __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
3622  __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
3623  NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
3625  &pVNetRootContext->FsAttrs;
3626  __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
3627  NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
3628  __notnull PMRX_FCB Fcb = RxContext->pFcb;
3629  __notnull PNFS41_FCB nfs41_fcb = (PNFS41_FCB)Fcb->Context;
3631  RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
3632 
3633  if (Fcb->pNetRoot->Type != NET_ROOT_DISK &&
3634  Fcb->pNetRoot->Type != NET_ROOT_WILD) {
3635  print_error("nfs41_Create: Unsupported NetRoot Type %u\n",
3636  Fcb->pNetRoot->Type);
3637  status = STATUS_NOT_SUPPORTED;
3638  goto out;
3639  }
3640 
3641  if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
3642  print_error("FCB_STATE_PAGING_FILE not implemented\n");
3643  status = STATUS_NOT_IMPLEMENTED;
3644  goto out;
3645  }
3646 
3647  if (!pNetRootContext->mounts_init) {
3648  print_error("nfs41_Create: No valid session established\n");
3650  goto out;
3651  }
3652 
3653  if (isStream(SrvOpen->pAlreadyPrefixedName)) {
3654  status = STATUS_NOT_SUPPORTED;
3655  goto out;
3656  }
3657 
3658  if (pVNetRootContext->read_only &&
3661  goto out;
3662  }
3663 
3664  /* if FCB was marked for deletion and opened multiple times, as soon
3665  * as first close happen, FCB transitions into delete_pending state
3666  * no more opens allowed
3667  */
3668  if (Fcb->OpenCount && nfs41_fcb->DeletePending) {
3669  status = STATUS_DELETE_PENDING;
3670  goto out;
3671  }
3672 
3673  /* ms-fsa: 3.1.5.1.2.1 page 68 */
3674  if (Fcb->OpenCount && nfs41_fcb->StandardInfo.DeletePending &&
3675  !(params->ShareAccess & FILE_SHARE_DELETE) &&
3676  (params->DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA |
3678  status = STATUS_SHARING_VIOLATION;
3679  goto out;
3680  }
3681 
3682  /* rdbss seems miss this sharing_violation check */
3683  if (Fcb->OpenCount && params->Disposition == FILE_SUPERSEDE) {
3684 #ifdef __REACTOS__
3685  if ((!RxContext->CurrentIrpSp->FileObject->SharedRead &&
3686  (params->DesiredAccess & FILE_READ_DATA)) ||
3687  ((!RxContext->CurrentIrpSp->FileObject->SharedWrite &&
3689  FILE_WRITE_ATTRIBUTES))) ||
3690  (!RxContext->CurrentIrpSp->FileObject->SharedDelete &&
3691  (params->DesiredAccess & DELETE)))) {
3692 #else
3693  if ((!RxContext->CurrentIrpSp->FileObject->SharedRead &&
3694  (params->DesiredAccess & FILE_READ_DATA)) ||
3695  (!RxContext->CurrentIrpSp->FileObject->SharedWrite &&
3698  (!RxContext->CurrentIrpSp->FileObject->SharedDelete &&
3699  (params->DesiredAccess & DELETE)))) {
3700 #endif
3701  status = STATUS_SHARING_VIOLATION;
3702  goto out;
3703  }
3704  }
3705  if (isFilenameTooLong(SrvOpen->pAlreadyPrefixedName, pVNetRootContext)) {
3706  status = STATUS_OBJECT_NAME_INVALID;
3707  goto out;
3708  }
3709 
3710  if (!areOpenParamsValid(params)) {
3711  status = STATUS_INVALID_PARAMETER;
3712  goto out;
3713  }
3714 
3715  /* from ms-fsa 3.1.5.1.1 page 56 */
3716  if ((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
3718  status = STATUS_CANNOT_DELETE;
3719  goto out;
3720  }
3721 
3722  if (ea) {
3723  /* ignore cygwin EAs when checking support and access */
3724  if (!AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength) &&
3725  !AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength) &&
3726  !AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
3727  if (!(FsAttrs->FileSystemAttributes & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)) {
3728  status = STATUS_EAS_NOT_SUPPORTED;
3729  goto out;
3730  }
3731  }
3732  } else if (RxContext->CurrentIrpSp->Parameters.Create.EaLength) {
3733  status = STATUS_INVALID_PARAMETER;
3734  goto out;
3735  }
3736 
3737 out:
3738  return status;
3739 }
3740 
3741 #ifdef __REACTOS__
3743 #else
3745 #endif
3746  IN OUT PRX_CONTEXT RxContext)
3747 {
3750  PNT_CREATE_PARAMETERS params = &RxContext->Create.NtCreateParameters;
3752  RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
3753  __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
3754  __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
3755  NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
3756  __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
3757  NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
3758  __notnull PMRX_FCB Fcb = RxContext->pFcb;
3759  __notnull PNFS41_FCB nfs41_fcb = (PNFS41_FCB)Fcb->Context;
3760  PNFS41_FOBX nfs41_fobx = NULL;
3761  BOOLEAN oldDeletePending = nfs41_fcb->StandardInfo.DeletePending;
3762 #ifdef ENABLE_TIMINGS
3763  LARGE_INTEGER t1, t2;
3765 #endif
3766 
3767  ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
3768 
3769 #ifdef DEBUG_OPEN
3770  DbgEn();
3771  print_debug_header(RxContext);
3772  print_nt_create_params(1, RxContext->Create.NtCreateParameters);
3773  if (ea) print_ea_info(0, ea);
3774 #endif
3775 
3776  status = check_nfs41_create_args(RxContext);
3777  if (status) goto out;
3778 
3779 #if defined(STORE_MOUNT_SEC_CONTEXT) && defined (USE_MOUNT_SEC_CONTEXT)
3780  status = nfs41_UpcallCreate(NFS41_OPEN, &pVNetRootContext->mount_sec_ctx,
3781 #else
3783 #endif
3784  pVNetRootContext->session, INVALID_HANDLE_VALUE,
3785  pNetRootContext->nfs41d_version,
3786  SrvOpen->pAlreadyPrefixedName, &entry);
3787  if (status) goto out;
3788 
3789  entry->u.Open.access_mask = params->DesiredAccess;
3790  entry->u.Open.access_mode = params->ShareAccess;
3791  entry->u.Open.attrs = params->FileAttributes;
3792  if (!(params->CreateOptions & FILE_DIRECTORY_FILE))
3793  entry->u.Open.attrs |= FILE_ATTRIBUTE_ARCHIVE;
3794  entry->u.Open.disp = params->Disposition;
3795  entry->u.Open.copts = params->CreateOptions;
3796  entry->u.Open.srv_open = SrvOpen;
3797  /* treat the NfsActOnLink ea as FILE_OPEN_REPARSE_POINT */
3798  if ((ea && AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength)) ||
3799  (entry->u.Open.access_mask & DELETE))
3800  entry->u.Open.copts |= FILE_OPEN_REPARSE_POINT;
3801  if (isDataAccess(params->DesiredAccess) || isOpen2Create(params->Disposition))
3802  entry->u.Open.open_owner_id = InterlockedIncrement(&open_owner_id);
3803  // if we are creating a file check if nfsv3attributes were passed in
3804  if (params->Disposition != FILE_OPEN && params->Disposition != FILE_OVERWRITE) {
3805  entry->u.Open.mode = 0777;
3806  if (ea && AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength)) {
3807  nfs3_attrs *attrs = (nfs3_attrs *)(ea->EaName + ea->EaNameLength + 1);
3808 #ifdef DEBUG_OPEN
3809  DbgP("creating file with mode %o\n", attrs->mode);
3810 #endif
3811  entry->u.Open.mode = attrs->mode;
3812  }
3814  entry->u.Open.mode = 0444;
3815  }
3816  if (entry->u.Open.disp == FILE_CREATE && ea &&
3817  AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
3818  /* for a cygwin symlink, given as a unicode string */
3819  entry->u.Open.symlink.Buffer = (PWCH)(ea->EaName + ea->EaNameLength + 1);
3820  entry->u.Open.symlink.MaximumLength = entry->u.Open.symlink.Length = ea->EaValueLength;
3821  }
3822 retry_on_link:
3823  if (ea && create_should_pass_ea(ea, params->Disposition)) {
3824  /* lock the extended attribute buffer for read access in user space */
3825  entry->u.Open.EaMdl = IoAllocateMdl(ea,
3826  RxContext->CurrentIrpSp->Parameters.Create.EaLength,
3827  FALSE, FALSE, NULL);
3828  if (entry->u.Open.EaMdl == NULL) {
3829  status = STATUS_INTERNAL_ERROR;
3830  RxFreePool(entry);
3831  goto out;
3832  }
3833  entry->u.Open.EaMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
3835  }
3836 
3837  status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
3838 #ifndef USE_MOUNT_SEC_CONTEXT
3839  SeDeleteClientSecurity(&entry->sec_ctx);
3840 #endif
3841  if (status) goto out;
3842 
3843  if (entry->u.Open.EaMdl) {
3844  MmUnlockPages(entry->u.Open.EaMdl);
3845  IoFreeMdl(entry->u.Open.EaMdl);
3846  }
3847 
3848  if (entry->status == NO_ERROR && entry->errno == ERROR_REPARSE) {
3849  /* symbolic link handling. when attempting to open a symlink when the
3850  * FILE_OPEN_REPARSE_POINT flag is not set, replace the filename with
3851  * the symlink target's by calling RxPrepareToReparseSymbolicLink()
3852  * and returning STATUS_REPARSE. the object manager will attempt to
3853  * open the new path, and return its handle for the original open */
3854  PRDBSS_DEVICE_OBJECT DeviceObject = RxContext->RxDeviceObject;
3855  PV_NET_ROOT VNetRoot = (PV_NET_ROOT)
3856  RxContext->pRelevantSrvOpen->pVNetRoot;
3857  PUNICODE_STRING VNetRootPrefix = &VNetRoot->PrefixEntry.Prefix;
3858  UNICODE_STRING AbsPath;
3859  PCHAR buf;
3860  BOOLEAN ReparseRequired;
3861 
3862  /* allocate the string for RxPrepareToReparseSymbolicLink(), and
3863  * format an absolute path "DeviceName+VNetRootName+symlink" */
3864  AbsPath.Length = DeviceObject->DeviceName.Length +
3865  VNetRootPrefix->Length + entry->u.Open.symlink.Length;
3866  AbsPath.MaximumLength = AbsPath.Length + sizeof(UNICODE_NULL);
3867  AbsPath.Buffer = RxAllocatePoolWithTag(NonPagedPool,
3868  AbsPath.MaximumLength, NFS41_MM_POOLTAG);
3869  if (AbsPath.Buffer == NULL) {
3871  goto out_free;
3872  }
3873 
3874  buf = (PCHAR)AbsPath.Buffer;
3875  RtlCopyMemory(buf, DeviceObject->DeviceName.Buffer,
3876  DeviceObject->DeviceName.Length);
3877  buf += DeviceObject->DeviceName.Length;
3878  RtlCopyMemory(buf, VNetRootPrefix->Buffer, VNetRootPrefix->Length);
3879  buf += VNetRootPrefix->Length;
3880  RtlCopyMemory(buf, entry->u.Open.symlink.Buffer,
3881  entry->u.Open.symlink.Length);
3882  RxFreePool(entry->u.Open.symlink.Buffer);
3883  buf += entry->u.Open.symlink.Length;
3884  *(PWCHAR)buf = UNICODE_NULL;
3885 
3886  status = RxPrepareToReparseSymbolicLink(RxContext,
3887  entry->u.Open.symlink_embedded, &AbsPath, TRUE, &ReparseRequired);
3888 #ifdef DEBUG_OPEN
3889  DbgP("RxPrepareToReparseSymbolicLink(%u, '%wZ') returned %08lX, "
3890  "FileName is '%wZ'\n", entry->u.Open.symlink_embedded,
3891  &AbsPath, status, &RxContext->CurrentIrpSp->FileObject->FileName);
3892 #endif
3893  if (status == STATUS_SUCCESS) {
3894  /* if a reparse is not required, reopen the link itself. this
3895  * happens with operations on cygwin symlinks, where the reparse
3896  * flag is not set */
3897  if (!ReparseRequired) {
3898  entry->u.Open.symlink.Length = 0;
3899  entry->u.Open.copts |= FILE_OPEN_REPARSE_POINT;
3900  goto retry_on_link;
3901  }
3902  status = STATUS_REPARSE;
3903  }
3904  goto out_free;
3905  }
3906 
3907  status = map_open_errors(entry->status,
3908  SrvOpen->pAlreadyPrefixedName->Length);
3909  if (status) {
3910 #ifdef DEBUG_OPEN
3911  print_open_error(1, status);
3912 #endif
3913  goto out_free;
3914  }
3915 
3916  if (!RxIsFcbAcquiredExclusive(Fcb)) {
3919  }
3920 
3921  RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
3922  if (RxContext->pFobx == NULL) {
3924  goto out_free;
3925  }
3926 #ifdef DEBUG_OPEN
3927  DbgP("nfs41_Create: created FOBX %p\n", RxContext->pFobx);
3928 #endif
3929  nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context;
3930  nfs41_fobx->nfs41_open_state = entry->open_state;
3931 #ifndef USE_MOUNT_SEC_CONTEXT
3932  status = nfs41_get_sec_ctx(SecurityImpersonation, &nfs41_fobx->sec_ctx);
3933  if (status)
3934  goto out_free;
3935 #else
3936  RtlCopyMemory(&nfs41_fobx->sec_ctx, &pVNetRootContext->mount_sec_ctx,
3937  sizeof(nfs41_fobx->sec_ctx));
3938 #endif
3939 
3940  // we get attributes only for data access and file (not directories)
3941  if (Fcb->OpenCount == 0 ||
3942  (Fcb->OpenCount > 0 &&
3943  nfs41_fcb->changeattr != entry->ChangeTime)) {
3944  FCB_INIT_PACKET InitPacket;
3945  RX_FILE_TYPE StorageType = FileTypeNotYetKnown;
3946  RtlCopyMemory(&nfs41_fcb->BasicInfo, &entry->u.Open.binfo,
3947  sizeof(entry->u.Open.binfo));
3948  RtlCopyMemory(&nfs41_fcb->StandardInfo, &entry->u.Open.sinfo,
3949  sizeof(entry->u.Open.sinfo));
3950  nfs41_fcb->mode = entry->u.Open.mode;
3951  nfs41_fcb->changeattr = entry->ChangeTime;
3952  if (((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
3953  !pVNetRootContext->read_only) || oldDeletePending)
3954  nfs41_fcb->StandardInfo.DeletePending = TRUE;
3955 
3956  RxFormInitPacket(InitPacket,
3957  &entry->u.Open.binfo.FileAttributes,
3958  &entry->u.Open.sinfo.NumberOfLinks,
3959  &entry->u.Open.binfo.CreationTime,
3960  &entry->u.Open.binfo.LastAccessTime,
3961  &entry->u.Open.binfo.LastWriteTime,
3962  &entry->u.Open.binfo.ChangeTime,
3963  &entry->u.Open.sinfo.AllocationSize,
3964  &entry->u.Open.sinfo.EndOfFile,
3965  &entry->u.Open.sinfo.EndOfFile);
3966 
3967  if (entry->u.Open.sinfo.Directory)
3968  StorageType = FileTypeDirectory;
3969  else
3970  StorageType = FileTypeFile;
3971 
3972  RxFinishFcbInitialization(Fcb, RDBSS_STORAGE_NTC(StorageType),
3973  &InitPacket);
3974  }
3975 #ifdef DEBUG_OPEN
3976  else
3977  DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
3978 
3979  print_basic_info(1, &nfs41_fcb->BasicInfo);
3980  print_std_info(1, &nfs41_fcb->StandardInfo);
3981 #endif
3982 
3983  /* aglo: 05/10/2012. it seems like always have to invalid the cache if the
3984  * file has been opened before and being opened again for data access.
3985  * If the file was opened before, RDBSS might have cached (unflushed) data
3986  * and by opening it again, we will not have the correct representation of
3987  * the file size and data content. fileio tests 208, 219, 221.
3988  */
3989  if (Fcb->OpenCount > 0 && (isDataAccess(params->DesiredAccess) ||
3990  nfs41_fcb->changeattr != entry->ChangeTime) &&
3991  !nfs41_fcb->StandardInfo.Directory) {
3993 #ifdef DEBUG_OPEN
3994  DbgP("nfs41_Create: reopening (changed) file %wZ\n",
3995  SrvOpen->pAlreadyPrefixedName);
3996 #endif
3997  RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
3998  }
3999  if (!nfs41_fcb->StandardInfo.Directory &&
4000  isDataAccess(params->DesiredAccess)) {
4001  nfs41_fobx->deleg_type = entry->u.Open.deleg_type;
4002 #ifdef DEBUG_OPEN
4003  DbgP("nfs41_Create: received delegation %d\n", entry->u.Open.deleg_type);
4004 #endif
4005  if (!(params->CreateOptions & FILE_WRITE_THROUGH) &&
4006  !pVNetRootContext->write_thru &&
4007  (entry->u.Open.deleg_type == 2 ||
4008  (params->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))) {
4009 #ifdef DEBUG_OPEN
4010  DbgP("nfs41_Create: enabling write buffering\n");
4011 #endif
4012  SrvOpen->BufferingFlags |=
4015  } else if (params->CreateOptions & FILE_WRITE_THROUGH ||
4016  pVNetRootContext->write_thru)
4017  nfs41_fobx->write_thru = TRUE;
4018  if (entry->u.Open.deleg_type >= 1 ||
4019  params->DesiredAccess & FILE_READ_DATA) {
4020 #ifdef DEBUG_OPEN
4021  DbgP("nfs41_Create: enabling read buffering\n");
4022 #endif
4023  SrvOpen->BufferingFlags |=
4026  }
4027  if (pVNetRootContext->nocache ||
4029 #ifdef DEBUG_OPEN
4030  DbgP("nfs41_Create: disabling buffering\n");
4031 #endif
4032  SrvOpen->BufferingFlags = FCB_STATE_DISABLE_LOCAL_BUFFERING;
4033  nfs41_fobx->nocache = TRUE;
4034  } else if (!entry->u.Open.deleg_type && !Fcb->OpenCount) {
4035  nfs41_fcb_list_entry *oentry;
4036 #ifdef DEBUG_OPEN
4037  DbgP("nfs41_Create: received no delegations: srv_open=%p "
4038  "ctime=%llu\n", SrvOpen, entry->ChangeTime);
4039 #endif
4042  if (oentry == NULL) {
4044  goto out_free;
4045  }
4046  oentry->fcb = RxContext->pFcb;
4047  oentry->nfs41_fobx = nfs41_fobx;
4048  oentry->session = pVNetRootContext->session;
4049  oentry->ChangeTime = entry->ChangeTime;
4050  oentry->skip = FALSE;
4051  nfs41_AddEntry(fcblistLock, openlist, oentry);
4052  }
4053  }
4054 
4055  if ((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
4056  !pVNetRootContext->read_only)
4057  nfs41_fcb->StandardInfo.DeletePending = TRUE;
4058 
4059  RxContext->Create.ReturnedCreateInformation =
4061 
4062  RxContext->pFobx->OffsetOfNextEaToReturn = 1;
4063 #ifndef __REACTOS__
4064  RxContext->CurrentIrp->IoStatus.Information =
4065  RxContext->Create.ReturnedCreateInformation;
4066 #endif
4067  status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
4068 
4069 out_free:
4070  if (entry)
4071  RxFreePool(entry);
4072 out:
4073 #ifdef ENABLE_TIMINGS
4075  if ((params->DesiredAccess & FILE_READ_DATA) ||
4076  (params->DesiredAccess & FILE_WRITE_DATA) ||
4077  (params->DesiredAccess & FILE_APPEND_DATA) ||
4078  (params->DesiredAccess & FILE_EXECUTE)) {
4079  InterlockedIncrement(&open.tops);
4080  InterlockedAdd64(&open.ticks, t2.QuadPart - t1.QuadPart);
4081 #ifdef ENABLE_INDV_TIMINGS
4082  DbgP("nfs41_Create open delta = %d op=%d sum=%d\n",
4083  t2.QuadPart - t1.QuadPart, open.tops, open.ticks);
4084 #endif
4085  } else {
4087  InterlockedAdd64(&lookup.ticks, t2.QuadPart - t1.QuadPart);
4088 #ifdef ENABLE_INDV_TIMINGS
4089  DbgP("nfs41_Create lookup delta = %d op=%d sum=%d\n",
4090  t2.QuadPart - t1.QuadPart, lookup.tops, lookup.ticks);
4091 #endif
4092  }
4093 #endif
4094 #ifdef DEBUG_OPEN
4095  DbgEx();
4096 #endif
4097  return status;
4098 }
4099 
4100 #ifdef __REACTOS__
4102 #else
4104 #endif
4105  IN OUT PRX_CONTEXT RxContext)
4106 {
4108  DbgEn();
4109  DbgEx();
4110  return status;
4111 }
4112 
4113 #ifdef __REACTOS__
4115 #else
4117 #endif
4118  IN OUT PRX_CONTEXT RxContext)
4119 {
4120  if (RxContext->pRelevantSrvOpen == NULL)
4121  return STATUS_SUCCESS;
4122  else return STATUS_MORE_PROCESSING_REQUIRED;
4123 }
4124 
4125 #ifdef __REACTOS__
4127 #else
4129 #endif
4130  IN OUT PRX_CONTEXT RxContext,
4131  IN PLARGE_INTEGER pNewFileSize,
4132  OUT PLARGE_INTEGER pNewAllocationSize)
4133 {
4134  NTSTATUS status = STATUS_SUCCESS;
4135  __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
4136 #ifdef DEBUG_CACHE
4137  PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
4138  DbgEn();
4139  print_debug_header(RxContext);
4140  DbgP("input: byte count 0x%x filesize 0x%x alloc size 0x%x\n",
4141  LowIoContext->ParamsFor.ReadWrite.ByteCount, *pNewFileSize,
4142  *pNewAllocationSize);
4143 #endif
4144  pNewAllocationSize->QuadPart = pNewFileSize->QuadPart + 8192;
4145  nfs41_fcb->StandardInfo.AllocationSize.QuadPart =
4146  pNewAllocationSize->QuadPart;
4147  nfs41_fcb->StandardInfo.EndOfFile.QuadPart = pNewFileSize->QuadPart;
4148 #ifdef DEBUG_CACHE
4149  DbgP("new filesize 0x%x new allocation size 0x%x\n", *pNewFileSize,
4150  *pNewAllocationSize);
4151 #endif
4152 #ifdef DEBUG_CACHE
4153  DbgEx();
4154 #endif
4155  return status;
4156 }
4157 
4159  PMRX_FCB fcb)
4160 {
4161  PLIST_ENTRY pEntry;
4162  nfs41_fcb_list_entry *cur;
4164 
4165  pEntry = openlist.head.Flink;
4166  while (!IsListEmpty(&openlist.head)) {
4167  cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
4169  if (cur->fcb == fcb) {
4170 #ifdef DEBUG_CLOSE
4171  DbgP("nfs41_remove_srvopen_entry: Found match for fcb=%p\n", fcb);
4172 #endif
4173  RemoveEntryList(pEntry);
4174  RxFreePool(cur);
4175  break;
4176  }
4177  if (pEntry->Flink == &openlist.head) {
4178 #ifdef DEBUG_CLOSE
4179  DbgP("nfs41_remove_srvopen_entry: reached EOL looking for fcb "
4180  "%p\n", fcb);
4181 #endif
4182  break;
4183  }
4184  pEntry = pEntry->Flink;
4185  }
4187 }
4188 
4190  DWORD status)
4191 {
4192  switch (status) {
4193  case NO_ERROR: return STATUS_SUCCESS;
4197  default:
4198  print_error("failed to map windows error %d to NTSTATUS; "
4199  "defaulting to STATUS_INTERNAL_ERROR\n", status);
4201  }
4202 }
4203 
4204 #ifdef __REACTOS__
4206 #else
4208 #endif
4209  IN OUT PRX_CONTEXT RxContext)
4210 {
4213  __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
4214  __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4215  NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
4216  __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
4217  NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
4218  __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
4219  __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
4220 #ifdef ENABLE_TIMINGS
4221  LARGE_INTEGER t1, t2;
4223 #endif
4224 
4225 #ifdef DEBUG_CLOSE
4226  DbgEn();
4227  print_debug_header(RxContext);
4228 #endif
4229 
4230  if (!nfs41_fobx->deleg_type && !nfs41_fcb->StandardInfo.Directory &&
4231  !RxContext->pFcb->OpenCount) {
4232  nfs41_remove_fcb_entry(RxContext->pFcb);
4233  }
4234 
4235  status = nfs41_UpcallCreate(NFS41_CLOSE, &nfs41_fobx->sec_ctx,
4236  pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
4237  pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4238  if (status) goto out;
4239 
4240  entry->u.Close.srv_open = SrvOpen;
4241  if (nfs41_fcb->StandardInfo.DeletePending)
4242  nfs41_fcb->DeletePending = TRUE;
4243  if (!RxContext->pFcb->OpenCount ||
4244  (nfs41_fcb->StandardInfo.DeletePending &&
4245  nfs41_fcb->StandardInfo.Directory))
4246  entry->u.Close.remove = nfs41_fcb->StandardInfo.DeletePending;
4247  if (!RxContext->pFcb->OpenCount)
4248  entry->u.Close.renamed = nfs41_fcb->Renamed;
4249 
4250  status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4251 #ifndef USE_MOUNT_SEC_CONTEXT
4252  SeDeleteClientSecurity(&nfs41_fobx->sec_ctx);
4253 #endif
4254  if (status) goto out;
4255 
4256  /* map windows ERRORs to NTSTATUS */
4257  status = map_close_errors(entry->status);
4258  RxFreePool(entry);
4259 out:
4260 #ifdef ENABLE_TIMINGS
4262  InterlockedIncrement(&close.tops);
4263  InterlockedAdd64(&close.ticks, t2.QuadPart - t1.QuadPart);