ReactOS  0.4.12-dev-43-g63b00d8
nfs41_rpc.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 "nfs41_ops.h"
23 #include "daemon_debug.h"
24 #include "nfs41_xdr.h"
25 #include "nfs41_callback.h"
26 #include "nfs41_driver.h" /* for AUTH_SYS, AUTHGSS_KRB5s defines */
27 
28 #include "rpc/rpc.h"
29 #define SECURITY_WIN32
30 #include <security.h>
31 #include "rpc/auth_sspi.h"
32 
34 {
35  struct timeval timeout = {10, 100};
36 
37  return clnt_call(client, 0,
39  (xdrproc_t)xdr_void, NULL, timeout);
40 }
41 
43  IN const netaddr4 *netaddr,
44  IN uint32_t wsize,
45  IN uint32_t rsize,
46  IN nfs41_rpc_clnt *rpc,
47  OUT OPTIONAL char *server_name,
48  OUT CLIENT **client_out)
49 {
51  struct netconfig *nconf;
52  struct netbuf *addr;
53  CLIENT *client;
54 
55  nconf = getnetconfigent(netaddr->netid);
56  if (nconf == NULL)
57  goto out;
58 
59  addr = uaddr2taddr(nconf, netaddr->uaddr);
60  if (addr == NULL)
61  goto out_free_conf;
62 
63  if (server_name) {
64  getnameinfo(addr->buf, addr->len, server_name, NI_MAXHOST, NULL, 0, 0);
65  dprintf(1, "servername is %s\n", server_name);
66  }
67  dprintf(1, "callback function %p args %p\n", nfs41_handle_callback, rpc);
68  client = clnt_tli_create(RPC_ANYFD, nconf, addr, NFS41_RPC_PROGRAM,
69  NFS41_RPC_VERSION, wsize, rsize, rpc ? proc_cb_compound_res : NULL,
70  rpc ? nfs41_handle_callback : NULL, rpc ? rpc : NULL);
71  if (client) {
72  *client_out = client;
73  status = NO_ERROR;
74  }
75 
76  freenetbuf(addr);
77 out_free_conf:
78  freenetconfigent(nconf);
79 out:
80  return status;
81 }
82 
84  IN const multi_addr4 *addrs,
85  IN uint32_t wsize,
86  IN uint32_t rsize,
87  IN nfs41_rpc_clnt *rpc,
88  OUT OPTIONAL char *server_name,
89  OUT CLIENT **client_out,
90  OUT uint32_t *addr_index)
91 {
93  uint32_t i;
94  for (i = 0; i < addrs->count; i++) {
95  status = get_client_for_netaddr(&addrs->arr[i],
96  wsize, rsize, rpc, server_name, client_out);
97  if (status == NO_ERROR) {
98  *addr_index = i;
99  break;
100  }
101  }
102  return status;
103 }
104 
107  IN char *server_name,
108  CLIENT *client
109  )
110 {
112 
113  switch (sec_flavor) {
114  case RPCSEC_AUTHGSS_KRB5:
115  client->cl_auth = authsspi_create_default(client, server_name,
117  break;
119  client->cl_auth = authsspi_create_default(client, server_name,
121  break;
123  client->cl_auth = authsspi_create_default(client, server_name,
125  break;
126  default:
127  eprintf("create_rpc_auth_client: unknown rpcsec flavor %d\n",
128  sec_flavor);
129  client->cl_auth = NULL;
130  }
131 
132  if (client->cl_auth == NULL) {
133  eprintf("nfs41_rpc_clnt_create: failed to create %s\n",
134  secflavorop2name(sec_flavor));
135  goto out;
136  } else
137  dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n",
138  secflavorop2name(sec_flavor));
139  status = 0;
140 out:
141  return status;
142 }
143 
144 /* Returns a client structure and an associated lock */
146  IN const multi_addr4 *addrs,
147  IN uint32_t wsize,
148  IN uint32_t rsize,
149  IN uint32_t uid,
150  IN uint32_t gid,
152  OUT nfs41_rpc_clnt **rpc_out)
153 {
154  CLIENT *client;
155  nfs41_rpc_clnt *rpc;
156  uint32_t addr_index;
157  int status;
158  char machname[MAXHOSTNAMELEN + 1];
159  gid_t gids[1];
160  bool_t needcb = 1;
161 
162  rpc = calloc(1, sizeof(nfs41_rpc_clnt));
163  if (rpc == NULL) {
164  status = GetLastError();
165  goto out;
166  }
167 #ifdef NO_CB_4_KRB5P
168  if (sec_flavor == RPCSEC_AUTHGSS_KRB5P)
169  needcb = 0;
170 #endif
171  rpc->needcb = needcb;
172  rpc->cond = CreateEvent(NULL, TRUE, FALSE, NULL);
173  if (rpc->cond == NULL) {
174  status = GetLastError();
175  eprintf("CreateEvent failed %d\n", status);
176  goto out_free_rpc_clnt;
177  }
178  status = get_client_for_multi_addr(addrs, wsize, rsize, needcb?rpc:NULL,
179  rpc->server_name, &client, &addr_index);
180  if (status) {
181  clnt_pcreateerror("connecting failed");
182  goto out_free_rpc_cond;
183  }
184  if (send_null(client) != RPC_SUCCESS) {
185  // XXX Do what here?
186  eprintf("nfs41_rpc_clnt_create: send_null failed\n");
187  status = ERROR_NETWORK_UNREACHABLE;
188  goto out_err_client;
189  }
190 
191  rpc->sec_flavor = sec_flavor;
192  if (sec_flavor == RPCSEC_AUTH_SYS) {
193  if (gethostname(machname, sizeof(machname)) == -1) {
194  eprintf("nfs41_rpc_clnt_create: gethostname failed\n");
195  goto out_err_client;
196  }
197  machname[sizeof(machname) - 1] = '\0';
198  client->cl_auth = authsys_create(machname, uid, gid, 0, gids);
199  if (client->cl_auth == NULL) {
200  eprintf("nfs41_rpc_clnt_create: failed to create rpc authsys\n");
201  status = ERROR_NETWORK_UNREACHABLE;
202  goto out_err_client;
203  }
204  } else {
205  status = create_rpcsec_auth_client(sec_flavor, rpc->server_name, client);
206  if (status) {
207  eprintf("nfs41_rpc_clnt_create: failed to establish security "
208  "context with %s\n", rpc->server_name);
209  status = ERROR_NETWORK_UNREACHABLE;
210  goto out_err_client;
211  } else
212  dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n",
213  secflavorop2name(sec_flavor));
214  }
215  rpc->rpc = client;
216 
217  /* keep a copy of the address and buffer sizes for reconnect */
218  memcpy(&rpc->addrs, addrs, sizeof(multi_addr4));
219  /* save the index of the address we connected to */
220  rpc->addr_index = addr_index;
221  rpc->wsize = wsize;
222  rpc->rsize = rsize;
223  rpc->is_valid_session = TRUE;
224  rpc->uid = uid;
225  rpc->gid = gid;
226 
227  //initialize rpc client lock
228  InitializeSRWLock(&rpc->lock);
229 
230  *rpc_out = rpc;
231 out:
232  return status;
233 out_err_client:
234  clnt_destroy(client);
235 out_free_rpc_cond:
236  CloseHandle(rpc->cond);
237 out_free_rpc_clnt:
238  free(rpc);
239  goto out;
240 }
241 
242 /* Frees resources allocated in clnt_create */
244  IN nfs41_rpc_clnt *rpc)
245 {
246  auth_destroy(rpc->rpc->cl_auth);
247  clnt_destroy(rpc->rpc);
248  CloseHandle(rpc->cond);
249  free(rpc);
250 }
251 
253 {
254  bool_t status = FALSE;
256  if (value) {
257  dprintf(1, "nfs41_rpc_renew_in_progress: setting value %d\n", *value);
258  rpc->in_recovery = *value;
259  if (!rpc->in_recovery)
260  SetEvent(rpc->cond);
261  } else {
262  status = rpc->in_recovery;
263  dprintf(1, "nfs41_rpc_renew_in_progress: returning value %d\n", status);
264  }
266  return status;
267 }
268 
270 {
271  bool_t status = 0;
273  if (rpc->version > version)
274  status = 1;
276  return status;
277 }
278 
279 static int rpc_reconnect(
280  IN nfs41_rpc_clnt *rpc)
281 {
282  CLIENT *client = NULL;
283  uint32_t addr_index;
284  int status;
285 
286  AcquireSRWLockExclusive(&rpc->lock);
287 
288  status = get_client_for_multi_addr(&rpc->addrs, rpc->wsize, rpc->rsize,
289  rpc->needcb?rpc:NULL, NULL, &client, &addr_index);
290  if (status)
291  goto out_unlock;
292 
293  if(rpc->sec_flavor == RPCSEC_AUTH_SYS)
294  client->cl_auth = rpc->rpc->cl_auth;
295  else {
296  auth_destroy(rpc->rpc->cl_auth);
297  status = create_rpcsec_auth_client(rpc->sec_flavor, rpc->server_name, client);
298  if (status) {
299  eprintf("Failed to reestablish security context\n");
300  status = ERROR_NETWORK_UNREACHABLE;
301  goto out_err_client;
302  }
303  }
304  if (send_null(client) != RPC_SUCCESS) {
305  eprintf("rpc_reconnect: send_null failed\n");
306  status = ERROR_NETWORK_UNREACHABLE;
307  goto out_err_client;
308  }
309 
310  clnt_destroy(rpc->rpc);
311  rpc->rpc = client;
312  rpc->addr_index = addr_index;
313  rpc->version++;
314  dprintf(1, "nfs41_send_compound: reestablished RPC connection\n");
315 
316 out_unlock:
317  ReleaseSRWLockExclusive(&rpc->lock);
318 
319  /* after releasing the rpc lock, send a BIND_CONN_TO_SESSION if
320  * we need to associate the connection with the backchannel */
321  if (status == NO_ERROR && rpc->needcb &&
322  rpc->client && rpc->client->session) {
323  status = nfs41_bind_conn_to_session(rpc,
324  rpc->client->session->session_id, CDFC4_BACK_OR_BOTH);
325  if (status)
326  eprintf("nfs41_bind_conn_to_session() failed with %s\n",
327  nfs_error_string(status));
328  status = NFS4_OK;
329  }
330  return status;
331 
332 out_err_client:
333  clnt_destroy(client);
334  goto out_unlock;
335 }
336 
338  IN nfs41_rpc_clnt *rpc,
339  IN char *inbuf,
340  OUT char *outbuf)
341 {
342  struct timeval timeout = {90, 100};
343  enum clnt_stat rpc_status;
344  int status, count = 0, one = 1, zero = 0;
346 
347  try_again:
348  AcquireSRWLockShared(&rpc->lock);
349  version = rpc->version;
350  rpc_status = clnt_call(rpc->rpc, 1,
353  timeout);
354  ReleaseSRWLockShared(&rpc->lock);
355 
356  if (rpc_status != RPC_SUCCESS) {
357  eprintf("clnt_call returned rpc_status = %s\n",
358  rpc_error_string(rpc_status));
359  switch(rpc_status) {
360  case RPC_CANTRECV:
361  case RPC_CANTSEND:
362  case RPC_TIMEDOUT:
363  case RPC_AUTHERROR:
364  if (++count > 3 || !rpc->is_valid_session) {
365  status = ERROR_NETWORK_UNREACHABLE;
366  break;
367  }
368  if (rpc_should_retry(rpc, version))
369  goto try_again;
370  while (rpc_renew_in_progress(rpc, NULL)) {
371  status = WaitForSingleObject(rpc->cond, INFINITE);
372  if (status != WAIT_OBJECT_0) {
373  dprintf(1, "rpc_renew_in_progress: WaitForSingleObject failed\n");
374  print_condwait_status(1, status);
375  status = ERROR_LOCK_VIOLATION;
376  goto out;
377  }
379  goto try_again;
380  }
381  rpc_renew_in_progress(rpc, &one);
382  if (rpc_status == RPC_AUTHERROR && rpc->sec_flavor != RPCSEC_AUTH_SYS) {
383  AcquireSRWLockExclusive(&rpc->lock);
384  auth_destroy(rpc->rpc->cl_auth);
385  status = create_rpcsec_auth_client(rpc->sec_flavor,
386  rpc->server_name, rpc->rpc);
387  ReleaseSRWLockExclusive(&rpc->lock);
388  if (status) {
389  eprintf("Failed to reestablish security context\n");
390  status = ERROR_NETWORK_UNREACHABLE;
391  goto out;
392  }
393  } else
394  if (rpc_reconnect(rpc))
395  eprintf("rpc_reconnect: Failed to reconnect!\n");
397  goto try_again;
398  default:
399  eprintf("UNHANDLED RPC_ERROR: %d\n", rpc_status);
400  status = ERROR_NETWORK_UNREACHABLE;
401  goto out;
402  }
403  goto out;
404  }
405 
406  status = 0;
407 out:
408  return status;
409 }
#define CreateEvent
Definition: winbase.h:3562
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
#define IN
Definition: typedefs.h:38
Definition: get.c:139
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
static enum clnt_stat send_null(CLIENT *client)
Definition: nfs41_rpc.c:33
int32_t bool_t
Definition: types.h:101
#define RPC_ANYFD
Definition: svc.h:328
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define free
Definition: debug_ros.c:5
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
void * buf
Definition: types.h:147
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
bool_t is_valid_session
Definition: nfs41.h:181
uint32_t rsize
Definition: nfs41.h:175
bool_t needcb
Definition: nfs41.h:183
void freenetbuf(struct netbuf *nbuf)
Definition: rpc_generic.c:633
int nfs41_rpc_clnt_create(IN const multi_addr4 *addrs, IN uint32_t wsize, IN uint32_t rsize, IN uint32_t uid, IN uint32_t gid, IN uint32_t sec_flavor, OUT nfs41_rpc_clnt **rpc_out)
Definition: nfs41_rpc.c:145
#define NO_ERROR
Definition: dderror.h:5
#define NFS41_RPC_PROGRAM
Definition: nfs41_const.h:78
int nfs41_handle_callback(void *rpc_clnt, void *cb, struct cb_compound_res **reply)
static double one
Definition: j0_y0.c:80
enum nfsstat4 nfs41_bind_conn_to_session(IN nfs41_rpc_clnt *rpc, IN const unsigned char *sessionid, IN enum channel_dir_from_client4 dir)
Definition: nfs41_ops.c:185
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
bool_t(* xdrproc_t)(XDR *,...)
Definition: xdr.h:144
GLenum GLclampf GLint i
Definition: glfuncs.h:14
UINT gid_t
Definition: types.h:89
INT WSAAPI gethostname(OUT char FAR *name, IN INT namelen)
Definition: getxbyxx.c:397
#define dprintf
Definition: regdump.c:33
const char * rpc_error_string(int status)
Definition: daemon_debug.c:482
bool_t in_recovery
Definition: nfs41.h:182
void freenetconfigent(struct netconfig *netconfigp)
Definition: getnetconfig.c:530
smooth NULL
Definition: ftsmooth.c:416
struct netconfig * getnetconfigent(char *netid) const
Definition: getnetconfig.c:432
static const WCHAR version[]
Definition: asmname.c:64
AUTH * authsspi_create_default(CLIENT *clnt, char *service, int svc)
Definition: auth_sspi.c:133
struct netbuf * uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
Definition: rpc_generic.c:619
static int get_client_for_multi_addr(IN const multi_addr4 *addrs, IN uint32_t wsize, IN uint32_t rsize, IN nfs41_rpc_clnt *rpc, OUT OPTIONAL char *server_name, OUT CLIENT **client_out, OUT uint32_t *addr_index)
Definition: nfs41_rpc.c:83
char server_name[NI_MAXHOST]
Definition: nfs41.h:180
AUTH * cl_auth
Definition: clnt.h:122
#define WAIT_OBJECT_0
Definition: winbase.h:387
static bool_t rpc_renew_in_progress(nfs41_rpc_clnt *rpc, int *value)
Definition: nfs41_rpc.c:252
bool_t nfs_decode_compound(XDR *xdr, caddr_t *pres)
Definition: nfs41_xdr.c:3625
uint32_t wsize
Definition: nfs41.h:174
multi_addr4 addrs
Definition: nfs41.h:172
int create_rpcsec_auth_client(IN uint32_t sec_flavor, IN char *server_name, CLIENT *client)
Definition: nfs41_rpc.c:105
static FILE * client
Definition: client.c:41
static FILE * out
Definition: regtests2xml.c:44
HANDLE cond
Definition: nfs41.h:170
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
uint32_t sec_flavor
Definition: nfs41.h:177
unsigned int len
Definition: types.h:146
#define NI_MAXHOST
Definition: ws2def.h:359
SRWLOCK lock
Definition: nfs41.h:169
uchar inbuf[M_BLOCK]
Definition: unzcrash.c:40
char * server_name
Definition: widl.c:135
static double zero
Definition: j0_y0.c:96
GLenum const GLvoid * addr
Definition: glext.h:9621
void clnt_pcreateerror(char *s) const
Definition: clnt_perror.c:307
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
CLIENT * clnt_tli_create(const SOCKET fd_in, const struct netconfig *nconf, struct netbuf *svcaddr, const rpcprog_t prog, const rpcvers_t vers, const uint sendsz, const uint recvsz, int(*callback_xdr)(void *, void *), int(*callback_function)(void *, void *, void **), void *callback_args)
Definition: clnt_generic.c:347
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
int nfs41_send_compound(IN nfs41_rpc_clnt *rpc, IN char *inbuf, OUT char *outbuf)
Definition: nfs41_rpc.c:337
uint32_t addr_index
Definition: nfs41.h:173
const char * secflavorop2name(DWORD sec_flavor)
Definition: daemon_debug.c:558
GLsizei const GLfloat * value
Definition: glext.h:6069
bool_t xdr_void(void)
Definition: xdr.c:92
#define NFS41_RPC_VERSION
Definition: nfs41_const.h:79
static int rpc_reconnect(IN nfs41_rpc_clnt *rpc)
Definition: nfs41_rpc.c:279
struct __rpc_client * rpc
Definition: nfs41.h:168
#define MAXHOSTNAMELEN
Definition: ftp.c:31
#define ERROR_NETWORK_UNREACHABLE
Definition: winerror.h:734
uint32_t uid
Definition: nfs41.h:178
#define getnameinfo
Definition: wspiapi.h:45
#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs)
Definition: clnt.h:202
UINT32 uint32_t
Definition: types.h:75
Definition: types.h:144
#define ERROR_LOCK_VIOLATION
Definition: winerror.h:136
#define calloc
Definition: rosglue.h:14
#define OUT
Definition: typedefs.h:39
bool_t nfs_encode_compound(XDR *xdr, caddr_t *pargs)
Definition: nfs41_xdr.c:3591
void nfs41_rpc_clnt_free(IN nfs41_rpc_clnt *rpc)
Definition: nfs41_rpc.c:243
#define authsys_create(c, i1, i2, i3, ip)
Definition: auth.h:323
static bool_t rpc_should_retry(nfs41_rpc_clnt *rpc, uint32_t version)
Definition: nfs41_rpc.c:269
sec_flavor
Definition: nfs41_ops.h:861
uint32_t gid
Definition: nfs41.h:179
bool_t proc_cb_compound_res(XDR *xdr, struct cb_compound_res *res)
Definition: callback_xdr.c:638
#define INFINITE
Definition: serial.h:102
static SERVICE_STATUS status
Definition: service.c:31
uint32_t version
Definition: nfs41.h:176
#define clnt_destroy(rh)
Definition: clnt.h:276
void print_condwait_status(int level, int status)
Definition: daemon_debug.c:513
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
#define auth_destroy(auth)
Definition: auth.h:259
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
clnt_stat
Definition: clnt_stat.h:21
static int get_client_for_netaddr(IN const netaddr4 *netaddr, IN uint32_t wsize, IN uint32_t rsize, IN nfs41_rpc_clnt *rpc, OUT OPTIONAL char *server_name, OUT CLIENT **client_out)
Definition: nfs41_rpc.c:42
uchar outbuf[M_BLOCK_OUT]
Definition: unzcrash.c:41
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68