[NFS]
[reactos.git] / reactos / drivers / filesystems / nfs / nfs41_driver.c
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;
84 DRIVER_DISPATCH ( nfs41_FsdDispatch );
85
86 struct _MINIRDR_DISPATCH nfs41_ops;
87 PRDBSS_DEVICE_OBJECT nfs41_dev;
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
101 KEVENT upcallEvent;
102 FAST_MUTEX upcallLock, downcallLock, fcblistLock;
103 FAST_MUTEX xidLock;
104 FAST_MUTEX openOwnerLock;
105
106 LONGLONG xid = 0;
107 LONG open_owner_id = 1;
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
123 INLINE BOOL AnsiStrEq(
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 {
133 DWORD type, mode, nlink, uid, gid, filler1;
134 LARGE_INTEGER size, used;
135 struct {
136 DWORD specdata1;
137 DWORD specdata2;
138 } rdev;
139 LONGLONG fsid, fileid;
140 LONGLONG atime, mtime, ctime;
141 } nfs3_attrs;
142 LARGE_INTEGER unix_time_diff; //needed to convert windows time to unix
143
144 enum ftype3 {
145 NF3REG = 1,
146 NF3DIR,
147 NF3BLK,
148 NF3CHR,
149 NF3LNK,
150 NF3SOCK,
151 NF3FIFO
152 };
153
154 typedef enum _nfs41_updowncall_state {
155 NFS41_WAITING_FOR_UPCALL,
156 NFS41_WAITING_FOR_DOWNCALL,
157 NFS41_DONE_PROCESSING,
158 NFS41_NOT_WAITING
159 } nfs41_updowncall_state;
160
161 #ifdef __REACTOS__
162 #undef _errno
163 #undef errno
164 #endif
165
166 typedef struct _updowncall_entry {
167 DWORD version;
168 LONGLONG xid;
169 DWORD opcode;
170 NTSTATUS status;
171 nfs41_updowncall_state state;
172 FAST_MUTEX lock;
173 LIST_ENTRY next;
174 KEVENT cond;
175 DWORD errno;
176 BOOLEAN async_op;
177 SECURITY_CLIENT_CONTEXT sec_ctx;
178 PSECURITY_CLIENT_CONTEXT psec_ctx;
179 HANDLE open_state;
180 HANDLE session;
181 PUNICODE_STRING filename;
182 PVOID buf;
183 ULONG buf_len;
184 ULONGLONG ChangeTime;
185 union {
186 struct {
187 PUNICODE_STRING srv_name;
188 PUNICODE_STRING root;
189 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
190 DWORD sec_flavor;
191 DWORD rsize;
192 DWORD wsize;
193 DWORD lease_time;
194 } Mount;
195 struct {
196 PMDL MdlAddress;
197 ULONGLONG offset;
198 PRX_CONTEXT rxcontext;
199 } ReadWrite;
200 struct {
201 LONGLONG offset;
202 LONGLONG length;
203 BOOLEAN exclusive;
204 BOOLEAN blocking;
205 } Lock;
206 struct {
207 ULONG count;
208 LOWIO_LOCK_LIST locks;
209 } Unlock;
210 struct {
211 FILE_BASIC_INFORMATION binfo;
212 FILE_STANDARD_INFORMATION sinfo;
213 UNICODE_STRING symlink;
214 ULONG access_mask;
215 ULONG access_mode;
216 ULONG attrs;
217 ULONG copts;
218 ULONG disp;
219 ULONG cattrs;
220 LONG open_owner_id;
221 DWORD mode;
222 HANDLE srv_open;
223 DWORD deleg_type;
224 BOOLEAN symlink_embedded;
225 PMDL EaMdl;
226 PVOID EaBuffer;
227 } Open;
228 struct {
229 HANDLE srv_open;
230 BOOLEAN remove;
231 BOOLEAN renamed;
232 } Close;
233 struct {
234 PUNICODE_STRING filter;
235 FILE_INFORMATION_CLASS InfoClass;
236 BOOLEAN restart_scan;
237 BOOLEAN return_single;
238 BOOLEAN initial_query;
239 PMDL mdl;
240 PVOID mdl_buf;
241 } QueryFile;
242 struct {
243 FILE_INFORMATION_CLASS InfoClass;
244 } SetFile;
245 struct {
246 DWORD mode;
247 } SetEa;
248 struct {
249 PVOID EaList;
250 ULONG EaListLength;
251 ULONG Overflow;
252 ULONG EaIndex;
253 BOOLEAN ReturnSingleEntry;
254 BOOLEAN RestartScan;
255 } QueryEa;
256 struct {
257 PUNICODE_STRING target;
258 BOOLEAN set;
259 } Symlink;
260 struct {
261 FS_INFORMATION_CLASS query;
262 } Volume;
263 struct {
264 SECURITY_INFORMATION query;
265 } Acl;
266 } u;
267
268 } nfs41_updowncall_entry;
269
270 typedef struct _updowncall_list {
271 LIST_ENTRY head;
272 } nfs41_updowncall_list;
273 nfs41_updowncall_list upcall, downcall;
274
275 typedef struct _nfs41_mount_entry {
276 LIST_ENTRY next;
277 LUID login_id;
278 HANDLE authsys_session;
279 HANDLE gss_session;
280 HANDLE gssi_session;
281 HANDLE gssp_session;
282 } nfs41_mount_entry;
283
284 typedef struct _nfs41_mount_list {
285 LIST_ENTRY head;
286 } 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");
332 DECLARE_CONST_UNICODE_STRING(SLASH, L"\\");
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 {
343 DWORD ReadSize;
344 DWORD WriteSize;
345 BOOLEAN ReadOnly;
346 BOOLEAN write_thru;
347 BOOLEAN nocache;
348 WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
349 UNICODE_STRING SrvName;
350 WCHAR mntpt_buffer[MAX_PATH];
351 UNICODE_STRING MntPt;
352 WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN];
353 UNICODE_STRING SecFlavor;
354 DWORD timeout;
355 } NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG;
356
357 typedef struct _NFS41_NETROOT_EXTENSION {
358 NODE_TYPE_CODE NodeTypeCode;
359 NODE_BYTE_SIZE NodeByteSize;
360 DWORD nfs41d_version;
361 BOOLEAN mounts_init;
362 FAST_MUTEX mountLock;
363 nfs41_mount_list mounts;
364 } NFS41_NETROOT_EXTENSION, *PNFS41_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
379 typedef struct _NFS41_V_NET_ROOT_EXTENSION {
380 NODE_TYPE_CODE NodeTypeCode;
381 NODE_BYTE_SIZE NodeByteSize;
382 HANDLE session;
383 FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
384 DWORD sec_flavor;
385 DWORD timeout;
386 USHORT MountPathLen;
387 BOOLEAN read_only;
388 BOOLEAN write_thru;
389 BOOLEAN nocache;
390 #define STORE_MOUNT_SEC_CONTEXT
391 #ifdef STORE_MOUNT_SEC_CONTEXT
392 SECURITY_CLIENT_CONTEXT mount_sec_ctx;
393 #endif
394 } NFS41_V_NET_ROOT_EXTENSION, *PNFS41_V_NET_ROOT_EXTENSION;
395 #define NFS41GetVNetRootExtension(pVNetRoot) \
396 (((pVNetRoot) == NULL) ? NULL : \
397 (PNFS41_V_NET_ROOT_EXTENSION)((pVNetRoot)->Context))
398
399 typedef struct _NFS41_FCB {
400 NODE_TYPE_CODE NodeTypeCode;
401 NODE_BYTE_SIZE NodeByteSize;
402 FILE_BASIC_INFORMATION BasicInfo;
403 FILE_STANDARD_INFORMATION StandardInfo;
404 BOOLEAN Renamed;
405 BOOLEAN DeletePending;
406 DWORD mode;
407 ULONGLONG changeattr;
408 } NFS41_FCB, *PNFS41_FCB;
409 #define NFS41GetFcbExtension(pFcb) \
410 (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context))
411
412 typedef struct _NFS41_FOBX {
413 NODE_TYPE_CODE NodeTypeCode;
414 NODE_BYTE_SIZE NodeByteSize;
415
416 HANDLE nfs41_open_state;
417 SECURITY_CLIENT_CONTEXT sec_ctx;
418 PVOID acl;
419 DWORD acl_len;
420 LARGE_INTEGER time;
421 DWORD deleg_type;
422 BOOLEAN write_thru;
423 BOOLEAN nocache;
424 } NFS41_FOBX, *PNFS41_FOBX;
425 #define NFS41GetFobxExtension(pFobx) \
426 (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
427
428 typedef struct _NFS41_SERVER_ENTRY {
429 PMRX_SRV_CALL pRdbssSrvCall;
430 WCHAR NameBuffer[SERVER_NAME_BUFFER_SIZE];
431 UNICODE_STRING Name; // the server name.
432 } NFS41_SERVER_ENTRY, *PNFS41_SERVER_ENTRY;
433
434 typedef struct _NFS41_DEVICE_EXTENSION {
435 NODE_TYPE_CODE NodeTypeCode;
436 NODE_BYTE_SIZE NodeByteSize;
437 PRDBSS_DEVICE_OBJECT DeviceObject;
438 ULONG ActiveNodes;
439 HANDLE SharedMemorySection;
440 DWORD nfs41d_version;
441 BYTE VolAttrs[VOL_ATTR_LEN];
442 DWORD VolAttrsLen;
443 HANDLE openlistHandle;
444 } NFS41_DEVICE_EXTENSION, *PNFS41_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 {
451 LIST_ENTRY next;
452 PMRX_FCB fcb;
453 HANDLE session;
454 PNFS41_FOBX nfs41_fobx;
455 ULONGLONG ChangeTime;
456 BOOLEAN skip;
457 } nfs41_fcb_list_entry;
458
459 typedef struct _nfs41_fcb_list {
460 LIST_ENTRY head;
461 } nfs41_fcb_list;
462 nfs41_fcb_list openlist;
463
464 typedef enum _NULMRX_STORAGE_TYPE_CODES {
465 NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00,
466 } NFS41_STORAGE_TYPE_CODES;
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
481 nfs41_init_driver_state nfs41_init_state = NFS41_INIT_DRIVER_STARTABLE;
482 nfs41_start_driver_state nfs41_start_state = NFS41_START_DRIVER_STARTABLE;
483
484 NTSTATUS map_readwrite_errors(DWORD status);
485
486 void print_debug_header(
487 PRX_CONTEXT RxContext)
488 {
489
490 PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp;
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 */
510 INLINE ULONG length_as_utf8(
511 PCUNICODE_STRING str)
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
518 NTSTATUS marshall_unicode_as_utf8(
519 IN OUT unsigned char **pos,
520 IN PCUNICODE_STRING str)
521 {
522 ANSI_STRING ansi;
523 ULONG ActualCount;
524 NTSTATUS status;
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
562 NTSTATUS marshal_nfs41_header(
563 nfs41_updowncall_entry *entry,
564 unsigned char *buf,
565 ULONG buf_len,
566 ULONG *len)
567 {
568 NTSTATUS status = STATUS_SUCCESS;
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) {
575 status = STATUS_INSUFFICIENT_RESOURCES;
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(
605 DWORD sec_flavor)
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 }
616 NTSTATUS marshal_nfs41_mount(
617 nfs41_updowncall_entry *entry,
618 unsigned char *buf,
619 ULONG buf_len,
620 ULONG *len)
621 {
622 NTSTATUS status = STATUS_SUCCESS;
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) {
639 status = STATUS_INSUFFICIENT_RESOURCES;
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
664 NTSTATUS marshal_nfs41_unmount(
665 nfs41_updowncall_entry *entry,
666 unsigned char *buf,
667 ULONG buf_len,
668 ULONG *len)
669 {
670 return marshal_nfs41_header(entry, buf, buf_len, len);
671 }
672
673 NTSTATUS marshal_nfs41_open(
674 nfs41_updowncall_entry *entry,
675 unsigned char *buf,
676 ULONG buf_len,
677 ULONG *len)
678 {
679 NTSTATUS status = STATUS_SUCCESS;
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) {
691 status = STATUS_INSUFFICIENT_RESOURCES;
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__
723 UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
724 #else
725 UserMode, MmCached, NULL, TRUE, NormalPagePriority);
726 #endif
727 if (entry->u.Open.EaBuffer == NULL) {
728 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
729 status = STATUS_INSUFFICIENT_RESOURCES;
730 goto out;
731 }
732 }
733 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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
753 NTSTATUS marshal_nfs41_rw(
754 nfs41_updowncall_entry *entry,
755 unsigned char *buf,
756 ULONG buf_len,
757 ULONG *len)
758 {
759 NTSTATUS status = STATUS_SUCCESS;
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) {
770 status = STATUS_INSUFFICIENT_RESOURCES;
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__
784 UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
785 #else
786 UserMode, MmCached, NULL, TRUE, NormalPagePriority);
787 #endif
788 if (entry->buf == NULL) {
789 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
790 status = STATUS_INSUFFICIENT_RESOURCES;
791 goto out;
792 }
793 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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
812 NTSTATUS marshal_nfs41_lock(
813 nfs41_updowncall_entry *entry,
814 unsigned char *buf,
815 ULONG buf_len,
816 ULONG *len)
817 {
818 NTSTATUS status = STATUS_SUCCESS;
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) {
828 status = STATUS_INSUFFICIENT_RESOURCES;
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
849 NTSTATUS marshal_nfs41_unlock(
850 nfs41_updowncall_entry *entry,
851 unsigned char *buf,
852 ULONG buf_len,
853 ULONG *len)
854 {
855 NTSTATUS status = STATUS_SUCCESS;
856 ULONG header_len = 0;
857 unsigned char *tmp = buf;
858 PLOWIO_LOCK_LIST lock;
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) {
867 status = STATUS_INSUFFICIENT_RESOURCES;
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
890 NTSTATUS marshal_nfs41_close(
891 nfs41_updowncall_entry *entry,
892 unsigned char *buf,
893 ULONG buf_len,
894 ULONG *len)
895 {
896 NTSTATUS status = STATUS_SUCCESS;
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) {
910 status = STATUS_INSUFFICIENT_RESOURCES;
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
933 NTSTATUS marshal_nfs41_dirquery(
934 nfs41_updowncall_entry *entry,
935 unsigned char *buf,
936 ULONG buf_len,
937 ULONG *len)
938 {
939 NTSTATUS status = STATUS_SUCCESS;
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) {
950 status = STATUS_INSUFFICIENT_RESOURCES;
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 =
968 MmMapLockedPagesSpecifyCache(entry->u.QueryFile.mdl,
969 #ifndef __REACTOS__
970 UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
971 #else
972 UserMode, MmCached, NULL, TRUE, NormalPagePriority);
973 #endif
974 if (entry->u.QueryFile.mdl_buf == NULL) {
975 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
976 status = STATUS_INSUFFICIENT_RESOURCES;
977 goto out;
978 }
979 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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
1000 NTSTATUS marshal_nfs41_filequery(
1001 nfs41_updowncall_entry *entry,
1002 unsigned char *buf,
1003 ULONG buf_len,
1004 ULONG *len)
1005 {
1006 NTSTATUS status = STATUS_SUCCESS;
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) {
1016 status = STATUS_INSUFFICIENT_RESOURCES;
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
1035 NTSTATUS marshal_nfs41_fileset(
1036 nfs41_updowncall_entry *entry,
1037 unsigned char *buf,
1038 ULONG buf_len,
1039 ULONG *len)
1040 {
1041 NTSTATUS status = STATUS_SUCCESS;
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) {
1052 status = STATUS_INSUFFICIENT_RESOURCES;
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
1072 NTSTATUS marshal_nfs41_easet(
1073 nfs41_updowncall_entry *entry,
1074 unsigned char *buf,
1075 ULONG buf_len,
1076 ULONG *len)
1077 {
1078 NTSTATUS status = STATUS_SUCCESS;
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) {
1089 status = STATUS_INSUFFICIENT_RESOURCES;
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
1110 NTSTATUS marshal_nfs41_eaget(
1111 nfs41_updowncall_entry *entry,
1112 unsigned char *buf,
1113 ULONG buf_len,
1114 ULONG *len)
1115 {
1116 NTSTATUS status = STATUS_SUCCESS;
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) {
1128 status = STATUS_INSUFFICIENT_RESOURCES;
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
1159 NTSTATUS marshal_nfs41_symlink(
1160 nfs41_updowncall_entry *entry,
1161 unsigned char *buf,
1162 ULONG buf_len,
1163 ULONG *len)
1164 {
1165 NTSTATUS status = STATUS_SUCCESS;
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) {
1177 status = STATUS_INSUFFICIENT_RESOURCES;
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
1200 NTSTATUS marshal_nfs41_volume(
1201 nfs41_updowncall_entry *entry,
1202 unsigned char *buf,
1203 ULONG buf_len,
1204 ULONG *len)
1205 {
1206 NTSTATUS status = STATUS_SUCCESS;
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) {
1216 status = STATUS_INSUFFICIENT_RESOURCES;
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
1230 NTSTATUS marshal_nfs41_getacl(
1231 nfs41_updowncall_entry *entry,
1232 unsigned char *buf,
1233 ULONG buf_len,
1234 ULONG *len)
1235 {
1236 NTSTATUS status = STATUS_SUCCESS;
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) {
1246 status = STATUS_INSUFFICIENT_RESOURCES;
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
1260 NTSTATUS marshal_nfs41_setacl(
1261 nfs41_updowncall_entry *entry,
1262 unsigned char *buf,
1263 ULONG buf_len,
1264 ULONG *len)
1265 {
1266 NTSTATUS status = STATUS_SUCCESS;
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) {
1277 status = STATUS_INSUFFICIENT_RESOURCES;
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
1296 NTSTATUS marshal_nfs41_shutdown(
1297 nfs41_updowncall_entry *entry,
1298 unsigned char *buf,
1299 ULONG buf_len,
1300 ULONG *len)
1301 {
1302 return marshal_nfs41_header(entry, buf, buf_len, len);
1303 }
1304
1305 void nfs41_invalidate_cache (
1306 IN PRX_CONTEXT RxContext)
1307 {
1308 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
1309 unsigned char *buf = LowIoContext->ParamsFor.IoCtl.pInputBuffer;
1310 ULONG flag = DISABLE_CACHING;
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))
1319 RxIndicateChangeOfBufferingStateForSrvOpen(
1320 srv_open->pFcb->pNetRoot->pSrvCall, srv_open,
1321 srv_open->Key, ULongToPtr(flag));
1322 }
1323
1324 NTSTATUS handle_upcall(
1325 IN PRX_CONTEXT RxContext,
1326 IN nfs41_updowncall_entry *entry,
1327 OUT ULONG *len)
1328 {
1329 NTSTATUS status = STATUS_SUCCESS;
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
1408 NTSTATUS nfs41_UpcallCreate(
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,
1414 IN PUNICODE_STRING filename,
1415 OUT nfs41_updowncall_entry **entry_out)
1416 {
1417 NTSTATUS status = STATUS_SUCCESS;
1418 nfs41_updowncall_entry *entry;
1419 SECURITY_SUBJECT_CONTEXT sec_ctx;
1420 SECURITY_QUALITY_OF_SERVICE sec_qos;
1421
1422 entry = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry),
1423 NFS41_MM_POOLTAG_UP);
1424 if (entry == NULL) {
1425 status = STATUS_INSUFFICIENT_RESOURCES;
1426 goto out;
1427 }
1428
1429 RtlZeroMemory(entry, sizeof(nfs41_updowncall_entry));
1430 entry->xid = InterlockedIncrement64(&xid);
1431 entry->opcode = opcode;
1432 entry->state = NFS41_WAITING_FOR_UPCALL;
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? */
1441 KeInitializeEvent(&entry->cond, SynchronizationEvent, FALSE);
1442 ExInitializeFastMutex(&entry->lock);
1443
1444 if (clnt_sec_ctx == NULL) {
1445 SeCaptureSubjectContext(&sec_ctx);
1446 sec_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
1447 sec_qos.ImpersonationLevel = SecurityImpersonation;
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
1468 NTSTATUS nfs41_UpcallWaitForReply(
1469 IN nfs41_updowncall_entry *entry,
1470 IN DWORD secs)
1471 {
1472 NTSTATUS status = STATUS_SUCCESS;
1473
1474 nfs41_AddEntry(upcallLock, upcall, entry);
1475 KeSetEvent(&upcallEvent, 0, FALSE);
1476 if (!entry->async_op) {
1477 LARGE_INTEGER timeout;
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 }
1530 nfs41_RemoveEntry(downcallLock, entry);
1531 out:
1532 return status;
1533 }
1534
1535 NTSTATUS nfs41_upcall(
1536 IN PRX_CONTEXT RxContext)
1537 {
1538 NTSTATUS status = STATUS_SUCCESS;
1539 nfs41_updowncall_entry *entry = NULL;
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,
1547 nfs41_updowncall_entry, next);
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)
1553 entry->state = NFS41_WAITING_FOR_DOWNCALL;
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
1577 void unmarshal_nfs41_header(
1578 nfs41_updowncall_entry *tmp,
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
1597 void unmarshal_nfs41_mount(
1598 nfs41_updowncall_entry *cur,
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
1614 VOID unmarshal_nfs41_setattr(
1615 nfs41_updowncall_entry *cur,
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
1625 NTSTATUS unmarshal_nfs41_rw(
1626 nfs41_updowncall_entry *cur,
1627 unsigned char **buf)
1628 {
1629 NTSTATUS status = STATUS_SUCCESS;
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);
1646 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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
1657 NTSTATUS unmarshal_nfs41_open(
1658 nfs41_updowncall_entry *cur,
1659 unsigned char **buf)
1660 {
1661 NTSTATUS status = STATUS_SUCCESS;
1662
1663 _SEH2_TRY {
1664 if (cur->u.Open.EaBuffer)
1665 MmUnmapLockedPages(cur->u.Open.EaBuffer, cur->u.Open.EaMdl);
1666 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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) {
1695 cur->status = STATUS_INSUFFICIENT_RESOURCES;
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
1714 NTSTATUS unmarshal_nfs41_dirquery(
1715 nfs41_updowncall_entry *cur,
1716 unsigned char **buf)
1717 {
1718 NTSTATUS status = STATUS_SUCCESS;
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);
1728 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
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)
1735 cur->status = STATUS_BUFFER_TOO_SMALL;
1736 cur->buf_len = buf_len;
1737
1738 return status;
1739 }
1740
1741 void unmarshal_nfs41_attrget(
1742 nfs41_updowncall_entry *cur,
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) {
1750 cur->status = STATUS_BUFFER_TOO_SMALL;
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
1759 void unmarshal_nfs41_eaget(
1760 nfs41_updowncall_entry *cur,
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
1773 void unmarshal_nfs41_getattr(
1774 nfs41_updowncall_entry *cur,
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
1785 NTSTATUS unmarshal_nfs41_getacl(
1786 nfs41_updowncall_entry *cur,
1787 unsigned char **buf)
1788 {
1789 NTSTATUS status = STATUS_SUCCESS;
1790 DWORD buf_len;
1791
1792 RtlCopyMemory(&buf_len, *buf, sizeof(DWORD));
1793 *buf += sizeof(DWORD);
1794 cur->buf = RxAllocatePoolWithTag(NonPagedPool,
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)
1802 cur->status = STATUS_BUFFER_TOO_SMALL;
1803 cur->buf_len = buf_len;
1804
1805 out:
1806 return status;
1807 }
1808
1809 void unmarshal_nfs41_symlink(
1810 nfs41_updowncall_entry *cur,
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) {
1819 cur->status = STATUS_BUFFER_TOO_SMALL;
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
1827 NTSTATUS nfs41_downcall(
1828 IN PRX_CONTEXT RxContext)
1829 {
1830 NTSTATUS status = STATUS_SUCCESS;
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
1840 tmp = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry),
1841 NFS41_MM_POOLTAG_DOWN);
1842 if (tmp == NULL) goto out;
1843
1844 unmarshal_nfs41_header(tmp, &buf);
1845
1846 ExAcquireFastMutex(&downcallLock);
1847 pEntry = &downcall.head;
1848 pEntry = pEntry->Flink;
1849 while (pEntry != NULL) {
1850 cur = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry,
1851 nfs41_updowncall_entry, next);
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 }
1860 ExReleaseFastMutex(&downcallLock);
1861 SeStopImpersonatingClient();
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);
1889 nfs41_RemoveEntry(downcallLock, cur);
1890 RxFreePool(cur);
1891 status = STATUS_UNSUCCESSFUL;
1892 goto out_free;
1893 }
1894 cur->state = NFS41_DONE_PROCESSING;
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 =
1948 map_readwrite_errors(cur->status);
1949 cur->u.ReadWrite.rxcontext->InformationToReturn = 0;
1950 }
1951 nfs41_RemoveEntry(downcallLock, cur);
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
1963 NTSTATUS nfs41_shutdown_daemon(
1964 DWORD version)
1965 {
1966 NTSTATUS status = STATUS_SUCCESS;
1967 nfs41_updowncall_entry *entry = NULL;
1968
1969 DbgEn();
1970 status = nfs41_UpcallCreate(NFS41_SHUTDOWN, NULL, INVALID_HANDLE_VALUE,
1971 INVALID_HANDLE_VALUE, version, NULL, &entry);
1972 if (status) goto out;
1973
1974 status = nfs41_UpcallWaitForReply(entry, UPCALL_TIMEOUT_DEFAULT);
1975 SeDeleteClientSecurity(&entry->sec_ctx);
1976 if (status) goto out;
1977
1978 RxFreePool(entry);
1979 out:
1980 DbgEx();
1981 return status;
1982 }
1983
1984 NTSTATUS SharedMemoryInit(
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
1996 RtlInitUnicodeString(&SectionName, NFS41_SHARED_MEMORY_NAME);
1997
1998 /* XXX: setting dacl=NULL grants access to everyone */
1999 status = RtlCreateSecurityDescriptor(&SecurityDesc,
2000 SECURITY_DESCRIPTOR_REVISION);
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;
2021 case STATUS_OBJECT_NAME_COLLISION:
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
2034 NTSTATUS SharedMemoryFree(
2035 IN HANDLE hSection)
2036 {
2037 NTSTATUS status;
2038 DbgEn();
2039 status = ZwClose(hSection);
2040 DbgEx();
2041 return status;
2042 }
2043
2044 #ifdef __REACTOS__
2045 NTSTATUS NTAPI nfs41_Start(
2046 #else
2047 NTSTATUS nfs41_Start(
2048 #endif
2049 IN OUT PRX_CONTEXT RxContext,
2050 IN OUT PRDBSS_DEVICE_OBJECT dev)
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);
2060 status = STATUS_INSUFFICIENT_RESOURCES;
2061 goto out;
2062 }
2063
2064 InterlockedCompareExchange((PLONG)&nfs41_start_state,
2065 NFS41_START_DRIVER_STARTED,
2066 NFS41_START_DRIVER_START_IN_PROGRESS);
2067 out:
2068 DbgEx();
2069 return status;
2070 }
2071
2072 #ifdef __REACTOS__
2073 NTSTATUS NTAPI nfs41_Stop(
2074 #else
2075 NTSTATUS nfs41_Stop(
2076 #endif
2077 IN OUT PRX_CONTEXT RxContext,
2078 IN OUT PRDBSS_DEVICE_OBJECT dev)
2079 {
2080 NTSTATUS status;
2081 NFS41GetDeviceExtension(RxContext, DevExt);
2082 DbgEn();
2083 status = SharedMemoryFree(DevExt->SharedMemorySection);
2084 DbgEx();
2085 return status;
2086 }
2087
2088 NTSTATUS GetConnectionHandle(
2089 IN PUNICODE_STRING ConnectionName,
2090 IN PVOID EaBuffer,
2091 IN ULONG EaLength,
2092 OUT PHANDLE Handle)
2093 {
2094 NTSTATUS status;
2095 IO_STATUS_BLOCK IoStatusBlock;
2096 OBJECT_ATTRIBUTES ObjectAttributes;
2097
2098 #ifdef DEBUG_MOUNT
2099 DbgEn();
2100 #endif
2101 InitializeObjectAttributes(&ObjectAttributes, ConnectionName,
2102 OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
2103
2104 print_error("Len %d Buf %p\n", EaLength, EaBuffer);
2105
2106 status = ZwCreateFile(Handle, SYNCHRONIZE, &ObjectAttributes,
2107 &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
2108 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2109 FILE_OPEN_IF,
2110 FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
2111 EaBuffer, EaLength);
2112
2113 #ifdef DEBUG_MOUNT
2114 DbgEx();
2115 #endif
2116 return status;
2117 }
2118
2119 NTSTATUS nfs41_GetConnectionInfoFromBuffer(
2120 IN PVOID Buffer,
2121 IN ULONG BufferLen,
2122 OUT PUNICODE_STRING pConnectionName,
2123 OUT PVOID *ppEaBuffer,
2124 OUT PULONG pEaLength)
2125 {
2126 NTSTATUS status = STATUS_SUCCESS;
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
2176 NTSTATUS nfs41_CreateConnection(
2177 IN PRX_CONTEXT RxContext,
2178 OUT PBOOLEAN PostToFsp)
2179 {
2180 NTSTATUS status = STATUS_SUCCESS;
2181 HANDLE Handle = INVALID_HANDLE_VALUE;
2182 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
2183 PVOID Buffer = LowIoContext->ParamsFor.IoCtl.pInputBuffer, EaBuffer;
2184 ULONG BufferLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength, EaLength;
2185 UNICODE_STRING FileName;
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
2231 NTSTATUS nfs41_unmount(
2232 HANDLE session,
2233 DWORD version,
2234 DWORD timeout)
2235 {
2236 NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
2237 nfs41_updowncall_entry *entry;
2238
2239 #ifdef DEBUG_MOUNT
2240 DbgEn();
2241 #endif
2242 status = nfs41_UpcallCreate(NFS41_UNMOUNT, NULL, session,
2243 INVALID_HANDLE_VALUE, version, NULL, &entry);
2244 SeDeleteClientSecurity(&entry->sec_ctx);
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
2273 NTSTATUS nfs41_DeleteConnection (
2274 IN PRX_CONTEXT RxContext,
2275 OUT PBOOLEAN PostToFsp)
2276 {
2277 NTSTATUS status = STATUS_INVALID_PARAMETER;
2278 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
2279 PWCHAR ConnectName = LowIoContext->ParamsFor.IoCtl.pInputBuffer;
2280 ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
2281 HANDLE Handle;
2282 UNICODE_STRING FileName;
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__
2336 NTSTATUS NTAPI nfs41_DevFcbXXXControlFile(
2337 #else
2338 NTSTATUS nfs41_DevFcbXXXControlFile(
2339 #endif
2340 IN OUT PRX_CONTEXT RxContext)
2341 {
2342 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
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) {
2355 case IRP_MJ_FILE_SYSTEM_CONTROL:
2356 status = STATUS_INVALID_DEVICE_REQUEST;
2357 break;
2358 case IRP_MJ_DEVICE_CONTROL:
2359 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
2360 print_fs_ioctl(0, fsop);
2361 switch (fsop) {
2362 case IOCTL_NFS41_INVALCACHE:
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 {
2420 PLIST_ENTRY Entry;
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
2475 status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
2476 break;
2477 }
2478 status = nfs41_DeleteConnection(RxContext, &RxContext->PostRequest);
2479 break;
2480 case IOCTL_NFS41_GETSTATE:
2481 state = RDR_NULL_STATE;
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) {
2487 case NFS41_START_DRIVER_STARTABLE:
2488 case NFS41_START_DRIVER_STOPPED:
2489 state = RDR_STOPPED;
2490 break;
2491 case NFS41_START_DRIVER_START_IN_PROGRESS:
2492 state = RDR_STARTING;
2493 break;
2494 case NFS41_START_DRIVER_STARTED:
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) {
2515 case NFS41_START_DRIVER_STARTABLE:
2516 (nfs41_start_driver_state)InterlockedCompareExchange(
2517 (PLONG)&nfs41_start_state,
2518 NFS41_START_DRIVER_START_IN_PROGRESS,
2519 NFS41_START_DRIVER_STARTABLE);
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);
2529 status = STATUS_MORE_PROCESSING_REQUIRED;
2530 }
2531 break;
2532 case NFS41_START_DRIVER_STARTED:
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);
2545 status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
2546 break;
2547 }
2548
2549 state = (nfs41_start_driver_state)InterlockedCompareExchange(
2550 (PLONG)&nfs41_start_state,
2551 NFS41_START_DRIVER_STARTABLE,
2552 NFS41_START_DRIVER_STARTED);
2553
2554 status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
2555 DbgP("RxStopMinirdr status %08lx\n", status);
2556 if (status == STATUS_PENDING && RxContext->PostRequest == TRUE )
2557 status = STATUS_MORE_PROCESSING_REQUIRED;
2558 break;
2559 default:
2560 status = STATUS_INVALID_DEVICE_REQUEST;
2561 };
2562 break;
2563 default:
2564 status = STATUS_INVALID_DEVICE_REQUEST;
2565 };
2566
2567 //DbgEx();
2568 return status;
2569 }
2570
2571 #ifndef __REACTOS__
2572 NTSTATUS _nfs41_CreateSrvCall(
2573 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
2574 {
2575 #else
2576 NTSTATUS NTAPI _nfs41_CreateSrvCall(
2577 PVOID pContext)
2578 {
2579 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext = pContext;
2580 #endif
2581 NTSTATUS status = STATUS_SUCCESS;
2582 PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
2583 PMRX_SRV_CALL pSrvCall;
2584 PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure =
2585 (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->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",
2606 pSrvCall->pSrvCallName, SERVER_NAME_BUFFER_SIZE);
2607 status = STATUS_NAME_TOO_LONG;
2608 goto out;
2609 }
2610
2611 /* Let's create our own representation of the server */
2612 pServerEntry = (PNFS41_SERVER_ENTRY)RxAllocatePoolWithTag(PagedPool,
2613 sizeof(NFS41_SERVER_ENTRY), NFS41_MM_POOLTAG);
2614 if (pServerEntry == NULL) {
2615 status = STATUS_INSUFFICIENT_RESOURCES;
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__
2652 NTSTATUS NTAPI nfs41_CreateSrvCall(
2653 #else
2654 NTSTATUS nfs41_CreateSrvCall(
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
2664 if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
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__
2690 NTSTATUS NTAPI nfs41_SrvCallWinnerNotify(
2691 #else
2692 NTSTATUS nfs41_SrvCallWinnerNotify(
2693 #endif
2694 IN OUT PMRX_SRV_CALL pSrvCall,
2695 IN BOOLEAN ThisMinirdrIsTheWinner,
2696 IN OUT PVOID pSrvCallContext)
2697 {
2698 NTSTATUS status = STATUS_SUCCESS;
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
2713 NTSTATUS map_mount_errors(
2714 DWORD status)
2715 {
2716 switch (status) {
2717 case NO_ERROR: return STATUS_SUCCESS;
2718 case ERROR_NETWORK_UNREACHABLE: return STATUS_NETWORK_UNREACHABLE;
2719 case ERROR_BAD_NET_RESP: return STATUS_UNEXPECTED_NETWORK_ERROR;
2720 case ERROR_BAD_NET_NAME: return STATUS_BAD_NETWORK_NAME;
2721 case ERROR_BAD_NETPATH: return STATUS_BAD_NETWORK_PATH;
2722 default:
2723 print_error("failed to map windows error %d to NTSTATUS; "
2724 "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status);
2725 return STATUS_INSUFFICIENT_RESOURCES;
2726 }
2727 }
2728
2729 NTSTATUS nfs41_mount(
2730 PNFS41_MOUNT_CONFIG config,
2731 DWORD sec_flavor,
2732 PHANDLE session,
2733 DWORD *version,
2734 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs)
2735 {
2736 NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
2737 nfs41_updowncall_entry *entry;
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);
2756 SeDeleteClientSecurity(&entry->sec_ctx);
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
2776 void nfs41_MountConfig_InitDefaults(
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
2799 NTSTATUS nfs41_MountConfig_ParseBoolean(
2800 IN PFILE_FULL_EA_INFORMATION Option,
2801 IN PUNICODE_STRING usValue,
2802 OUT PBOOLEAN Value)
2803 {
2804 NTSTATUS status = STATUS_SUCCESS;
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
2818 NTSTATUS nfs41_MountConfig_ParseDword(
2819 IN PFILE_FULL_EA_INFORMATION Option,
2820 IN PUNICODE_STRING usValue,
2821 OUT PDWORD Value,
2822 IN DWORD Minimum,
2823 IN DWORD Maximum)
2824 {
2825 NTSTATUS status = STATUS_INVALID_PARAMETER;
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
2847 NTSTATUS nfs41_MountConfig_ParseOptions(
2848 IN PFILE_FULL_EA_INFORMATION EaBuffer,
2849 IN ULONG EaLength,
2850 IN OUT PNFS41_MOUNT_CONFIG Config)
2851 {
2852 NTSTATUS status = STATUS_SUCCESS;
2853 PFILE_FULL_EA_INFORMATION Option;
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,
2881 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,
2886 MOUNT_CONFIG_RW_SIZE_MAX);
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,
2891 MOUNT_CONFIG_RW_SIZE_MAX);
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
2927 NTSTATUS has_nfs_prefix(
2928 IN PUNICODE_STRING SrvCallName,
2929 IN PUNICODE_STRING NetRootName)
2930 {
2931 NTSTATUS status = STATUS_BAD_NETWORK_NAME;
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
2945 NTSTATUS map_sec_flavor(
2946 IN PUNICODE_STRING sec_flavor_name,
2947 OUT PDWORD sec_flavor)
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
2961 NTSTATUS nfs41_GetLUID(
2962 PLUID id)
2963 {
2964 NTSTATUS status = STATUS_SUCCESS;
2965 SECURITY_SUBJECT_CONTEXT sec_ctx;
2966 SECURITY_QUALITY_OF_SERVICE sec_qos;
2967 SECURITY_CLIENT_CONTEXT clnt_sec_ctx;
2968
2969 SeCaptureSubjectContext(&sec_ctx);
2970 sec_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
2971 sec_qos.ImpersonationLevel = SecurityIdentification;
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
2994 NTSTATUS nfs41_get_sec_ctx(
2995 IN enum _SECURITY_IMPERSONATION_LEVEL level,
2996 OUT PSECURITY_CLIENT_CONTEXT out_ctx)
2997 {
2998 NTSTATUS status;
2999 SECURITY_SUBJECT_CONTEXT ctx;
3000 SECURITY_QUALITY_OF_SERVICE sec_qos;
3001
3002 SeCaptureSubjectContext(&ctx);
3003 sec_qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
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
3015 SeReleaseSubjectContext(&ctx);
3016
3017 return status;
3018 }
3019
3020 #ifdef __REACTOS__
3021 NTSTATUS NTAPI nfs41_CreateVNetRoot(
3022 #else
3023 NTSTATUS nfs41_CreateVNetRoot(
3024 #endif
3025 IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
3026 {
3027 NTSTATUS status = STATUS_SUCCESS;
3028 NFS41_MOUNT_CONFIG *Config;
3029 __notnull PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)
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 NFS41