ReactOS 0.4.16-dev-303-g11d5cb8
nfs41_client.c
Go to the documentation of this file.
1/* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
3 *
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
6 *
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 */
21
22#include <windows.h>
23#include <stdio.h>
24#include <time.h>
25#include <winsock2.h>
26#include <iphlpapi.h> /* for GetAdaptersAddresses() */
27#include <wincrypt.h> /* for Crypt*() functions */
28#include <winsock2.h> /* for hostent struct */
29
30#include "tree.h"
31#include "delegation.h"
32#include "daemon_debug.h"
33#include "nfs41_ops.h"
34
35
37 IN bool_t is_data)
38{
40 if (is_data)
42 else
44 return flags;
45}
46
49{
50 enum pnfs_status pnfsstat;
51 int status = NO_ERROR;
52
53 /* initialize the pnfs layout and device lists for metadata clients */
54 pnfsstat = pnfs_layout_list_create(&client->layouts);
55 if (pnfsstat) {
57 goto out;
58 }
59 pnfsstat = pnfs_file_device_list_create(&client->devices);
60 if (pnfsstat) {
62 goto out_err_layouts;
63 }
64out:
65 return status;
66
67out_err_layouts:
69 client->layouts = NULL;
70 goto out;
71}
72
73static int update_server(
75 IN const char *server_scope,
76 IN const server_owner4 *owner)
77{
79 int status;
80
81 /* find a server matching the owner.major_id and scope */
82 status = nfs41_server_find_or_create(owner->so_major_id,
83 server_scope, nfs41_rpc_netaddr(client->rpc), &server);
84 if (status)
85 goto out;
86
87 /* if the server is the same, we now have an extra reference. if
88 * the servers are different, we still need to deref the old server.
89 * so both cases can be treated the same */
90 if (client->server)
92 client->server = server;
93out:
94 return status;
95}
96
99 IN const nfs41_exchange_id_res *exchangeid)
100{
101 client->clnt_id = exchangeid->clientid;
102 client->seq_id = exchangeid->sequenceid;
103 client->roles = exchangeid->flags & EXCHGID4_FLAG_MASK_PNFS;
104 return update_server(client, exchangeid->server_scope,
105 &exchangeid->server_owner);
106}
107
109 IN nfs41_rpc_clnt *rpc,
110 IN const client_owner4 *owner,
111 IN bool_t is_data,
112 IN const nfs41_exchange_id_res *exchangeid,
113 OUT nfs41_client **client_out)
114{
115 int status;
117
118 client = calloc(1, sizeof(nfs41_client));
119 if (client == NULL) {
121 goto out_err_rpc;
122 }
123
124 memcpy(&client->owner, owner, sizeof(client_owner4));
125 client->rpc = rpc;
126 client->is_data = is_data;
127
128 status = update_exchangeid_res(client, exchangeid);
129 if (status)
130 goto out_err_client;
131
132 list_init(&client->state.opens);
133 list_init(&client->state.delegations);
134 InitializeCriticalSection(&client->state.lock);
135
136 //initialize a lock used to protect access to client id and client id seq#
137 InitializeSRWLock(&client->exid_lock);
138
139 InitializeConditionVariable(&client->recovery.cond);
140 InitializeCriticalSection(&client->recovery.lock);
141
143 if (status) {
144 eprintf("pnfs_client_init() failed with %d\n", status);
145 goto out_err_client;
146 }
147 *client_out = client;
148out:
149 return status;
150out_err_client:
151 nfs41_client_free(client); /* also calls nfs41_rpc_clnt_free() */
152 goto out;
153out_err_rpc:
155 goto out;
156}
157
158static void dprint_roles(
159 IN int level,
160 IN uint32_t roles)
161{
162 dprintf(level, "roles: %s%s%s\n",
163 (roles & EXCHGID4_FLAG_USE_NON_PNFS) ? "USE_NON_PNFS " : "",
164 (roles & EXCHGID4_FLAG_USE_PNFS_MDS) ? "USE_PNFS_MDS " : "",
165 (roles & EXCHGID4_FLAG_USE_PNFS_DS) ? "USE_PNFS_DS" : "");
166}
167
170{
171 nfs41_exchange_id_res exchangeid = { 0 };
172 int status;
173
174 status = nfs41_exchange_id(client->rpc, &client->owner,
175 nfs41_exchange_id_flags(client->is_data), &exchangeid);
176 if (status) {
177 eprintf("nfs41_exchange_id() failed with %d\n", status);
179 goto out;
180 }
181
182 if (client->is_data) { /* require USE_PNFS_DS */
183 if ((exchangeid.flags & EXCHGID4_FLAG_USE_PNFS_DS) == 0) {
184 eprintf("client expected USE_PNFS_DS\n");
186 goto out;
187 }
188 } else { /* require USE_NON_PNFS or USE_PNFS_MDS */
189 if ((exchangeid.flags & EXCHGID4_FLAG_USE_NON_PNFS) == 0 &&
190 (exchangeid.flags & EXCHGID4_FLAG_USE_PNFS_MDS) == 0) {
191 eprintf("client expected USE_NON_PNFS OR USE_PNFS_MDS\n");
193 goto out;
194 }
195 }
196
197 dprint_roles(2, exchangeid.flags);
198
199 AcquireSRWLockExclusive(&client->exid_lock);
200 status = update_exchangeid_res(client, &exchangeid);
201 ReleaseSRWLockExclusive(&client->exid_lock);
202out:
203 return status;
204}
205
208{
209 dprintf(2, "nfs41_client_free(%llu)\n", client->clnt_id);
211 if (client->session) nfs41_session_free(client->session);
212 nfs41_destroy_clientid(client->rpc, client->clnt_id);
213 if (client->server) nfs41_server_deref(client->server);
215 if (client->layouts) pnfs_layout_list_free(client->layouts);
216 if (client->devices) pnfs_file_device_list_free(client->devices);
217 DeleteCriticalSection(&client->state.lock);
218 DeleteCriticalSection(&client->recovery.lock);
219 free(client);
220}
221
222
223/* client_owner generation
224 * we choose to use MAC addresses to generate a client_owner value that
225 * is unique to a machine and persists over restarts. because the client
226 * can have multiple network adapters/addresses, we take each adapter into
227 * account. the specification suggests that "for privacy reasons, it is
228 * best to perform some one-way function," so we apply an md5 hash to the
229 * sorted list of MAC addresses */
230
231/* References:
232 * RFC 5661: 2.4. Client Identifiers and Client Owners
233 * http://tools.ietf.org/html/rfc5661#section-2.4
234 *
235 * MSDN: GetAdaptersAddresses Function
236 * http://msdn.microsoft.com/en-us/library/aa365915%28VS.85%29.aspx
237 *
238 * MSDN: Example C Program: Creating an MD5 Hash from File Content
239 * http://msdn.microsoft.com/en-us/library/aa382380%28VS.85%29.aspx */
240
241
242/* use an rbtree to sort mac address entries */
243struct mac_entry {
244 RB_ENTRY(mac_entry) rbnode;
247};
248
249int mac_cmp(struct mac_entry *lhs, struct mac_entry *rhs)
250{
251 const int diff = rhs->length - lhs->length;
252 return diff ? diff : strncmp((const char*)lhs->address,
253 (const char*)rhs->address, lhs->length);
254}
256RB_GENERATE(mac_tree, mac_entry, rbnode, mac_cmp)
257
259 IN struct mac_tree *root,
262{
263 struct mac_entry *entry;
264
265 entry = calloc(1, sizeof(struct mac_entry));
266 if (entry == NULL)
267 return;
268
269 entry->address = address;
270 entry->length = length;
271
272 if (RB_INSERT(mac_tree, root, entry))
273 free(entry);
274}
275
276static int adapter_valid(
277 IN const IP_ADAPTER_ADDRESSES *addr)
278{
279 /* ignore generic interfaces whose address is not unique */
280 switch (addr->IfType) {
282 case IF_TYPE_TUNNEL:
283 return 0;
284 }
285 /* must have an address */
286 if (addr->PhysicalAddressLength == 0)
287 return 0;
288#ifndef __REACTOS__
289 /* must support ip */
290 return addr->Ipv4Enabled || addr->Ipv6Enabled;
291#else
292 return 1;
293#endif
294}
295
298{
300 struct mac_tree rbtree = RB_INITIALIZER(rbtree);
301 struct mac_entry *entry, *node;
302 ULONG len;
304
305 /* start with enough room for DEFAULT_MINIMUM_ENTITIES */
306 len = DEFAULT_MINIMUM_ENTITIES * sizeof(IP_ADAPTER_ADDRESSES);
307
308 do {
310 /* reallocate the buffer until we can fit all of it */
311 tmp = realloc(addrs, len);
312 if (tmp == NULL) {
314 goto out;
315 }
316 addrs = tmp;
317 status = GetAdaptersAddresses(AF_UNSPEC,
318 GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_SKIP_ANYCAST |
319 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME |
320 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_UNICAST,
321 NULL, addrs, &len);
322 } while (status == ERROR_BUFFER_OVERFLOW);
323
324 if (status) {
325 eprintf("GetAdaptersAddresses() failed with %d\n", status);
326 goto out;
327 }
328
329 /* get the mac address of each adapter */
330 for (addr = addrs; addr; addr = addr->Next)
331 if (adapter_valid(addr))
332 mac_entry_insert(&rbtree, addr->PhysicalAddress,
333 addr->PhysicalAddressLength);
334
335 /* require at least one valid address */
336 if (RB_EMPTY(&rbtree)) {
338 eprintf("GetAdaptersAddresses() did not return "
339 "any valid mac addresses, failing with %d.\n", status);
340 goto out;
341 }
342
343 RB_FOREACH_SAFE(entry, mac_tree, &rbtree, node) {
344 RB_REMOVE(mac_tree, &rbtree, entry);
345
346 if (!CryptHashData(hash, entry->address, entry->length, 0)) {
348 eprintf("CryptHashData() failed with %d\n", status);
349 /* don't break here, we need to free the rest */
350 }
351 free(entry);
352 }
353out:
354 free(addrs);
355 return status;
356}
357
359 IN const char *name,
361 OUT client_owner4 *owner)
362{
367 const ULONGLONG time_created = GetTickCount64();
368 int status;
369 char username[UNLEN + 1];
370 DWORD len = UNLEN + 1;
371
372 if (!GetUserNameA(username, &len)) {
374 eprintf("GetUserName() failed with %d\n", status);
375 goto out;
376 }
377
378 /* owner.verifier = "time created" */
379 memcpy(owner->co_verifier, &time_created, sizeof(time_created));
380
381 /* set up the md5 hash generator */
385 eprintf("CryptAcquireContext() failed with %d\n", status);
386 goto out;
387 }
388 if (!CryptCreateHash(context, CALG_MD5, 0, 0, &hash)) {
390 eprintf("CryptCreateHash() failed with %d\n", status);
391 goto out_context;
392 }
393
394 if (!CryptHashData(hash, (const BYTE*)&sec_flavor, (DWORD)sizeof(sec_flavor), 0)) {
396 eprintf("CryptHashData() failed with %d\n", status);
397 goto out_hash;
398 }
399
400 if (!CryptHashData(hash, (const BYTE*)username, (DWORD)strlen(username), 0)) {
402 eprintf("CryptHashData() failed with %d\n", status);
403 goto out_hash;
404 }
405
406 if (!CryptHashData(hash, (const BYTE*)name, (DWORD)strlen(name), 0)) {
408 eprintf("CryptHashData() failed with %d\n", status);
409 goto out_hash;
410 }
411
412 /* add the mac address from each applicable adapter to the hash */
414 if (status) {
415 eprintf("hash_mac_addrs() failed with %d\n", status);
416 goto out_hash;
417 }
418
419 /* extract the hash size (should always be 16 for md5) */
420 buffer = (PBYTE)&owner->co_ownerid_len;
421 length = (DWORD)sizeof(DWORD);
424 eprintf("CryptGetHashParam(size) failed with %d\n", status);
425 goto out_hash;
426 }
427 /* extract the hash buffer */
428 buffer = owner->co_ownerid;
429 length = owner->co_ownerid_len;
432 eprintf("CryptGetHashParam(val) failed with %d\n", status);
433 goto out_hash;
434 }
435
436out_hash:
438out_context:
440out:
441 return status;
442}
ULONGLONG WINAPI GetTickCount64(VOID)
Definition: GetTickCount64.c:9
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static void list_init(struct list_entry *head)
Definition: list.h:51
#define RB_EMPTY(head)
Definition: tree.h:321
#define RB_INSERT(name, x, y)
Definition: tree.h:724
#define RB_HEAD(name, type)
Definition: tree.h:294
#define RB_ENTRY(type)
Definition: tree.h:308
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:743
#define RB_REMOVE(name, x, y)
Definition: tree.h:725
#define RB_GENERATE(name, type, field, cmp)
Definition: tree.h:398
#define RB_INITIALIZER(root)
Definition: tree.h:299
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define NO_ERROR
Definition: dderror.h:5
#define realloc
Definition: debug_ros.c:6
#define free
Definition: debug_ros.c:5
void nfs41_client_delegation_free(IN nfs41_client *client)
Definition: delegation.c:828
#define NULL
Definition: types.h:112
int32_t bool_t
Definition: types.h:101
UINT32 uint32_t
Definition: types.h:75
BOOL WINAPI GetUserNameA(LPSTR lpszName, LPDWORD lpSize)
Definition: misc.c:246
BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash)
Definition: crypt.c:740
BOOL WINAPI CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
Definition: crypt.c:1610
BOOL WINAPI CryptDestroyHash(HCRYPTHASH hHash)
Definition: crypt.c:890
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
Definition: crypt.c:648
BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
Definition: crypt.c:1771
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:8
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:36
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:29
VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable)
Definition: sync.c:22
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint level
Definition: gl.h:1546
GLuint address
Definition: glext.h:9393
GLuint buffer
Definition: glext.h:5915
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum const GLvoid * addr
Definition: glext.h:9621
GLenum GLsizei len
Definition: glext.h:6722
static PIP_ADAPTER_ADDRESSES
Definition: iphlpapi.c:76
#define GAA_FLAG_SKIP_FRIENDLY_NAME
#define GAA_FLAG_SKIP_UNICAST
#define IF_TYPE_TUNNEL
Definition: ipifcons.h:151
#define IF_TYPE_SOFTWARE_LOOPBACK
Definition: ipifcons.h:44
#define DEFAULT_MINIMUM_ENTITIES
Definition: iptypes.h:29
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static WCHAR username[]
Definition: url.c:32
int nfs41_server_find_or_create(IN const char *server_owner_major_id, IN const char *server_scope, IN const netaddr4 *addr, OUT nfs41_server **server_out)
Definition: nfs41_server.c:221
void nfs41_server_deref(IN nfs41_server *server)
Definition: nfs41_server.c:155
void nfs41_session_free(IN nfs41_session *session)
static __inline netaddr4 * nfs41_rpc_netaddr(IN nfs41_rpc_clnt *rpc)
Definition: nfs41.h:500
void nfs41_rpc_clnt_free(IN nfs41_rpc_clnt *rpc)
Definition: nfs41_rpc.c:243
int nfs41_client_owner(IN const char *name, IN uint32_t sec_flavor, OUT client_owner4 *owner)
Definition: nfs41_client.c:358
static int adapter_valid(IN const IP_ADAPTER_ADDRESSES *addr)
Definition: nfs41_client.c:276
static int update_server(IN nfs41_client *client, IN const char *server_scope, IN const server_owner4 *owner)
Definition: nfs41_client.c:73
static DWORD hash_mac_addrs(IN HCRYPTHASH hash)
Definition: nfs41_client.c:296
int mac_cmp(struct mac_entry *lhs, struct mac_entry *rhs)
Definition: nfs41_client.c:249
static void dprint_roles(IN int level, IN uint32_t roles)
Definition: nfs41_client.c:158
uint32_t nfs41_exchange_id_flags(IN bool_t is_data)
Definition: nfs41_client.c:36
static int pnfs_client_init(IN nfs41_client *client)
Definition: nfs41_client.c:47
int nfs41_client_create(IN nfs41_rpc_clnt *rpc, IN const client_owner4 *owner, IN bool_t is_data, IN const nfs41_exchange_id_res *exchangeid, OUT nfs41_client **client_out)
Definition: nfs41_client.c:108
static int update_exchangeid_res(IN nfs41_client *client, IN const nfs41_exchange_id_res *exchangeid)
Definition: nfs41_client.c:97
void nfs41_client_free(IN nfs41_client *client)
Definition: nfs41_client.c:206
static void mac_entry_insert(IN struct mac_tree *root, IN PBYTE address, IN ULONG length)
Definition: nfs41_client.c:258
int nfs41_client_renew(IN nfs41_client *client)
Definition: nfs41_client.c:168
int nfs41_exchange_id(IN nfs41_rpc_clnt *rpc, IN client_owner4 *owner, IN uint32_t flags_in, OUT nfs41_exchange_id_res *res_out)
Definition: nfs41_ops.c:36
int nfs41_destroy_clientid(IN nfs41_rpc_clnt *rpc, IN uint64_t clientid)
Definition: nfs41_ops.c:242
@ EXCHGID4_FLAG_SUPP_MOVED_REFER
Definition: nfs41_ops.h:95
@ EXCHGID4_FLAG_USE_PNFS_MDS
Definition: nfs41_ops.h:101
@ EXCHGID4_FLAG_MASK_PNFS
Definition: nfs41_ops.h:104
@ EXCHGID4_FLAG_USE_NON_PNFS
Definition: nfs41_ops.h:100
@ EXCHGID4_FLAG_USE_PNFS_DS
Definition: nfs41_ops.h:102
sec_flavor
Definition: nfs41_ops.h:861
#define DWORD
Definition: nt_native.h:44
BYTE * PBYTE
Definition: pedump.c:66
enum pnfs_status pnfs_file_device_list_create(OUT struct pnfs_file_device_list **devices_out)
Definition: pnfs_device.c:124
enum pnfs_status pnfs_layout_list_create(OUT struct pnfs_layout_list **layouts_out)
Definition: pnfs_layout.c:121
pnfs_status
Definition: pnfs.h:58
void pnfs_layout_list_free(IN struct pnfs_layout_list *layouts)
Definition: pnfs_layout.c:139
void pnfs_file_device_list_free(IN struct pnfs_file_device_list *devices)
Definition: pnfs_device.c:144
#define dprintf
Definition: regdump.c:33
static FILE * out
Definition: regtests2xml.c:44
#define calloc
Definition: rosglue.h:14
static FILE * client
Definition: client.c:41
#define UNLEN
Definition: sspi.c:28
Definition: http.c:7252
Definition: _hash_fun.h:40
Definition: nfs41_client.c:243
Definition: name.c:39
Definition: ps.c:97
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
Definition: dlist.c:348
static rfbScreenInfoPtr server
Definition: vnc.c:74
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define HP_HASHSIZE
Definition: wincrypt.h:2184
#define PROV_RSA_FULL
Definition: wincrypt.h:2039
#define CRYPT_VERIFYCONTEXT
Definition: wincrypt.h:2069
ULONG_PTR HCRYPTPROV
Definition: wincrypt.h:46
#define CALG_MD5
Definition: wincrypt.h:1805
ULONG_PTR HCRYPTHASH
Definition: wincrypt.h:50
#define CryptAcquireContext
Definition: wincrypt.h:4164
#define HP_HASHVAL
Definition: wincrypt.h:2183
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
#define ERROR_BAD_NET_RESP
Definition: winerror.h:150
#define AF_UNSPEC
Definition: winsock.h:344
unsigned char BYTE
Definition: xxhash.c:193