1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
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.
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.
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
31 #include <lmcons.h> /* UNLEN for GetUserName() */
32 #include <iphlpapi.h> /* for GetNetworkParam() */
33 #include "nfs41_driver.h" /* for NFS41_USER_DEVICE_NAME_A */
34 #include "nfs41_np.h" /* for NFS41NP_SHARED_MEMORY */
37 #include "daemon_debug.h"
41 //#define MAX_NUM_THREADS 128
42 #define MAX_NUM_THREADS 1
43 DWORD NFS41D_VERSION
= 0;
46 static const char FILE_NETCONFIG
[] = "C:\\ReactOS\\System32\\drivers\\etc\\netconfig";
50 char localdomain_name
[NFS41_HOSTNAME_LEN
];
51 int default_uid
= 666;
52 int default_gid
= 777;
54 #ifndef STANDALONE_NFSD //make sure to define it in "sources" not here
56 HANDLE stop_event
= NULL
;
58 typedef struct _nfs41_process_thread
{
61 } nfs41_process_thread
;
63 static int map_user_to_ids(nfs41_idmapper
*idmapper
, uid_t
*uid
, gid_t
*gid
)
65 char username
[UNLEN
+ 1];
66 DWORD len
= UNLEN
+ 1;
67 int status
= NO_ERROR
;
69 if (!GetUserNameA(username
, &len
)) {
70 status
= GetLastError();
71 eprintf("GetUserName() failed with %d\n", status
);
74 dprintf(1, "map_user_to_ids: mapping user %s\n", username
);
76 if (nfs41_idmap_name_to_ids(idmapper
, username
, uid
, gid
)) {
77 /* instead of failing for auth_sys, fall back to 'nobody' uid/gid */
85 static unsigned int WINAPI
thread_main(void *args
)
87 nfs41_idmapper
*idmapper
= (nfs41_idmapper
*)args
;
90 // buffer used to process upcall, assumed to be fixed size.
91 // if we ever need to handle non-cached IO, need to make it dynamic
92 unsigned char outbuf
[UPCALL_BUF_SIZE
], inbuf
[UPCALL_BUF_SIZE
];
93 DWORD inbuf_len
= UPCALL_BUF_SIZE
, outbuf_len
;
96 pipe
= CreateFile(NFS41_USER_DEVICE_NAME_A
, GENERIC_READ
| GENERIC_WRITE
,
97 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
99 if (pipe
== INVALID_HANDLE_VALUE
)
101 eprintf("Unable to open upcall pipe %d\n", GetLastError());
102 return GetLastError();
106 status
= DeviceIoControl(pipe
, IOCTL_NFS41_READ
, NULL
, 0,
107 outbuf
, UPCALL_BUF_SIZE
, (LPDWORD
)&outbuf_len
, NULL
);
109 eprintf("IOCTL_NFS41_READ failed %d\n", GetLastError());
113 status
= upcall_parse(outbuf
, (uint32_t)outbuf_len
, &upcall
);
115 upcall
.status
= status
;
119 /* map username to uid/gid */
120 status
= map_user_to_ids(idmapper
, &upcall
.uid
, &upcall
.gid
);
122 upcall
.status
= status
;
126 if (upcall
.opcode
== NFS41_SHUTDOWN
) {
127 DbgPrint("Shutdown\n");
128 printf("Shutting down..\n");
132 status
= upcall_handle(&upcall
);
135 dprintf(1, "writing downcall: xid=%lld opcode=%s status=%d "
136 "get_last_error=%d\n", upcall
.xid
, opcode2string(upcall
.opcode
),
137 upcall
.status
, upcall
.last_error
);
139 upcall_marshall(&upcall
, inbuf
, (uint32_t)inbuf_len
, (uint32_t*)&outbuf_len
);
141 dprintf(2, "making a downcall: outbuf_len %ld\n\n", outbuf_len
);
142 status
= DeviceIoControl(pipe
, IOCTL_NFS41_WRITE
,
143 inbuf
, inbuf_len
, NULL
, 0, (LPDWORD
)&outbuf_len
, NULL
);
145 eprintf("IOCTL_NFS41_WRITE failed with %d xid=%lld opcode=%s\n",
146 GetLastError(), upcall
.xid
, opcode2string(upcall
.opcode
));
147 upcall_cancel(&upcall
);
149 if (upcall
.status
!= NFSD_VERSION_MISMATCH
)
150 upcall_cleanup(&upcall
);
154 return GetLastError();
157 #ifndef STANDALONE_NFSD
160 DbgPrint("Setting stop event\n");
162 SetEvent(stop_event
);
166 typedef struct _nfsd_args
{
171 static bool_t
check_for_files()
175 char config_path
[MAX_PATH
];
177 if (GetSystemDirectoryA(config_path
, ARRAYSIZE(config_path
)))
179 StringCchCatA(config_path
, ARRAYSIZE(config_path
), "\\drivers\\etc\\netconfig");
183 StringCchCopyA(config_path
, ARRAYSIZE(config_path
), "C:\\ReactOS\\system32\\drivers\\etc\\netconfig");
186 fd
= fopen(config_path
, "r");
189 fd
= fopen(FILE_NETCONFIG
, "r");
193 fprintf(stderr
,"nfsd() failed to open file '%s'\n", config_path
);
195 fprintf(stderr
,"nfsd() failed to open file '%s'\n", FILE_NETCONFIG
);
203 static void PrintUsage()
205 fprintf(stderr
, "Usage: nfsd.exe -d <debug_level> --noldap "
206 "--uid <non-zero value> --gid\n");
208 static bool_t
parse_cmdlineargs(int argc
, TCHAR
*argv
[], nfsd_args
*out
)
213 out
->debug_level
= 1;
214 out
->ldap_enable
= TRUE
;
216 /* parse command line */
217 for (i
= 1; i
< argc
; i
++) {
218 if (argv
[i
][0] == TEXT('-')) {
219 if (_tcscmp(argv
[i
], TEXT("-h")) == 0) { /* help */
223 else if (_tcscmp(argv
[i
], TEXT("-d")) == 0) { /* debug level */
226 fprintf(stderr
, "Missing debug level value\n");
230 out
->debug_level
= _ttoi(argv
[i
]);
232 else if (_tcscmp(argv
[i
], TEXT("--noldap")) == 0) { /* no LDAP */
233 out
->ldap_enable
= FALSE
;
235 else if (_tcscmp(argv
[i
], TEXT("--uid")) == 0) { /* no LDAP, setting default uid */
238 fprintf(stderr
, "Missing uid value\n");
242 default_uid
= _ttoi(argv
[i
]);
244 fprintf(stderr
, "Invalid (or missing) anonymous uid value of %d\n",
249 else if (_tcscmp(argv
[i
], TEXT("--gid")) == 0) { /* no LDAP, setting default gid */
252 fprintf(stderr
, "Missing gid value\n");
256 default_gid
= _ttoi(argv
[i
]);
259 fprintf(stderr
, "Unrecognized option '%s', disregarding.\n", argv
[i
]);
262 fprintf(stdout
, "parse_cmdlineargs: debug_level %d ldap is %d\n",
263 out
->debug_level
, out
->ldap_enable
);
267 static void print_getaddrinfo(struct addrinfo
*ptr
)
269 char ipstringbuffer
[46];
270 DWORD ipbufferlength
= 46;
272 dprintf(1, "getaddrinfo response flags: 0x%x\n", ptr
->ai_flags
);
273 switch (ptr
->ai_family
) {
274 case AF_UNSPEC
: dprintf(1, "Family: Unspecified\n"); break;
276 dprintf(1, "Family: AF_INET IPv4 address %s\n",
277 inet_ntoa(((struct sockaddr_in
*)ptr
->ai_addr
)->sin_addr
));
280 if (WSAAddressToString((LPSOCKADDR
)ptr
->ai_addr
, (DWORD
)ptr
->ai_addrlen
,
281 NULL
, ipstringbuffer
, &ipbufferlength
))
282 dprintf(1, "WSAAddressToString failed with %u\n", WSAGetLastError());
284 dprintf(1, "Family: AF_INET6 IPv6 address %s\n", ipstringbuffer
);
286 case AF_NETBIOS
: dprintf(1, "AF_NETBIOS (NetBIOS)\n"); break;
287 default: dprintf(1, "Other %ld\n", ptr
->ai_family
); break;
289 dprintf(1, "Canonical name: %s\n", ptr
->ai_canonname
);
292 static int getdomainname()
295 PFIXED_INFO net_info
= NULL
;
297 BOOLEAN flag
= FALSE
;
299 status
= GetNetworkParams(net_info
, &size
);
300 if (status
!= ERROR_BUFFER_OVERFLOW
) {
301 eprintf("getdomainname: GetNetworkParams returned %d\n", status
);
304 net_info
= calloc(1, size
);
305 if (net_info
== NULL
) {
306 status
= GetLastError();
309 status
= GetNetworkParams(net_info
, &size
);
311 eprintf("getdomainname: GetNetworkParams returned %d\n", status
);
315 if (net_info
->DomainName
[0] == '\0') {
316 struct addrinfo
*result
= NULL
, *ptr
= NULL
, hints
= { 0 };
317 char hostname
[NI_MAXHOST
], servInfo
[NI_MAXSERV
];
319 hints
.ai_socktype
= SOCK_STREAM
;
320 hints
.ai_protocol
= IPPROTO_TCP
;
322 status
= getaddrinfo(net_info
->HostName
, NULL
, &hints
, &result
);
324 status
= WSAGetLastError();
325 eprintf("getdomainname: getaddrinfo failed with %d\n", status
);
329 for (ptr
=result
; ptr
!= NULL
; ptr
=ptr
->ai_next
) {
330 print_getaddrinfo(ptr
);
332 switch (ptr
->ai_family
) {
335 status
= getnameinfo((struct sockaddr
*)ptr
->ai_addr
,
336 (socklen_t
)ptr
->ai_addrlen
, hostname
, NI_MAXHOST
,
337 servInfo
, NI_MAXSERV
, NI_NAMEREQD
);
340 dprintf(1, "getnameinfo failed %d\n", WSAGetLastError());
344 dprintf(1, "getnameinfo failed %d, forcing name\n", WSAGetLastError());
345 memcpy(hostname
, "reactos.home", sizeof("reactos.home"));
350 size_t i
, len
= strlen(hostname
);
352 dprintf(1, "getdomainname: hostname %s %d\n", hostname
, len
);
353 for (i
= 0; i
< len
; i
++)
359 memcpy(localdomain_name
, &hostname
[i
+1], len
-i
);
360 dprintf(1, "getdomainname: domainname %s %d\n",
361 localdomain_name
, strlen(localdomain_name
));
371 status
= ERROR_INTERNAL_ERROR
;
372 eprintf("getdomainname: unable to get a domain name. "
373 "Set this machine's domain name:\n"
374 "System > ComputerName > Change > More > mydomain\n");
376 freeaddrinfo(result
);
378 dprintf(1, "domain name is %s\n", net_info
->DomainName
);
379 memcpy(localdomain_name
, net_info
->DomainName
,
380 strlen(net_info
->DomainName
));
381 localdomain_name
[strlen(net_info
->DomainName
)] = '\0';
389 #ifdef STANDALONE_NFSD
390 void __cdecl
_tmain(int argc
, TCHAR
*argv
[])
392 VOID
ServiceStart(DWORD argc
, LPTSTR
*argv
)
395 DWORD status
= 0, len
;
396 // handle to our drivers
398 nfs41_process_thread tids
[MAX_NUM_THREADS
];
399 nfs41_idmapper
*idmapper
= NULL
;
403 if (!check_for_files())
405 if (!parse_cmdlineargs(argc
, argv
, &cmd_args
))
407 set_debug_level(cmd_args
.debug_level
);
411 /* Start the kernel part */
413 HANDLE hSvcMan
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
416 HANDLE hSvc
= OpenService(hSvcMan
, "nfs41_driver", SERVICE_ALL_ACCESS
);
419 SERVICE_STATUS SvcSt
;
420 QueryServiceStatus(hSvc
, &SvcSt
);
421 if (SvcSt
.dwCurrentState
!= SERVICE_RUNNING
)
423 if (StartService(hSvc
, 0, NULL
))
425 dprintf(1, "NFS41 driver started\n");
429 eprintf("Driver failed to start: %d\n", GetLastError());
434 eprintf("Driver in state: %x\n", SvcSt
.dwCurrentState
);
437 CloseServiceHandle(hSvc
);
441 eprintf("Failed to open service: %d\n", GetLastError());
444 CloseServiceHandle(hSvcMan
);
448 eprintf("Failed to open service manager: %d\n", GetLastError());
454 /* dump memory leaks to stderr on exit; this requires the debug heap,
455 /* available only when built in debug mode under visual studio -cbodley */
456 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF
| _CRTDBG_LEAK_CHECK_DF
);
457 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
458 #pragma warning (push)
459 #pragma warning (disable : 4306) /* conversion from 'int' to '_HFILE' of greater size */
460 _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
);
461 #pragma warning (pop)
462 dprintf(1, "debug mode. dumping memory leaks to stderr on exit.\n");
464 /* acquire and store in global memory current dns domain name.
469 nfs41_server_list_init();
471 if (cmd_args
.ldap_enable
) {
472 status
= nfs41_idmap_create(&idmapper
);
474 eprintf("id mapping initialization failed with %d\n", status
);
479 NFS41D_VERSION
= GetTickCount();
480 dprintf(1, "NFS41 Daemon starting: version %d\n", NFS41D_VERSION
);
482 pipe
= CreateFile(NFS41_USER_DEVICE_NAME_A
, GENERIC_READ
| GENERIC_WRITE
,
483 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
485 if (pipe
== INVALID_HANDLE_VALUE
)
487 eprintf("Unable to open upcall pipe %d\n", GetLastError());
491 dprintf(1, "starting nfs41 mini redirector\n");
492 status
= DeviceIoControl(pipe
, IOCTL_NFS41_START
,
493 &NFS41D_VERSION
, sizeof(DWORD
), NULL
, 0, (LPDWORD
)&len
, NULL
);
495 eprintf("IOCTL_NFS41_START failed with %d\n",
500 #ifndef STANDALONE_NFSD
501 DbgPrint("WaitEvent\n");
503 stop_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
504 if (stop_event
== NULL
)
508 for (i
= 0; i
< MAX_NUM_THREADS
; i
++) {
509 tids
[i
].handle
= (HANDLE
)_beginthreadex(NULL
, 0, thread_main
,
510 idmapper
, 0, &tids
[i
].tid
);
511 if (tids
[i
].handle
== INVALID_HANDLE_VALUE
) {
512 status
= GetLastError();
513 eprintf("_beginthreadex failed %d\n", status
);
517 #ifndef STANDALONE_NFSD
518 // report the status to the service control manager.
519 if (!ReportStatusToSCMgr(SERVICE_RUNNING
, NO_ERROR
, 0))
521 DbgPrint("Starting wait\n");
522 WaitForSingleObject(stop_event
, INFINITE
);
524 //This can be changed to waiting on an array of handles and using waitformultipleobjects
525 dprintf(1, "Parent waiting for children threads\n");
526 for (i
= 0; i
< MAX_NUM_THREADS
; i
++)
527 WaitForSingleObject(tids
[i
].handle
, INFINITE
);
529 dprintf(1, "Parent woke up!!!!\n");
534 if (idmapper
) nfs41_idmap_free(idmapper
);
536 #ifndef STANDALONE_NFSD