ReactOS  0.4.14-dev-599-g2d4d3f5
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,
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);
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 
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:
117  break;
121  break;
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",
135  goto out;
136  } else
137  dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n",
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
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");
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");
202  goto out_err_client;
203  }
204  } else {
206  if (status) {
207  eprintf("nfs41_rpc_clnt_create: failed to establish security "
208  "context with %s\n", rpc->server_name);
210  goto out_err_client;
211  } else
212  dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n",
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:
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");
301  goto out_err_client;
302  }
303  }
304  if (send_null(client) != RPC_SUCCESS) {
305  eprintf("rpc_reconnect: send_null failed\n");
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) {
324  rpc->client->session->session_id, CDFC4_BACK_OR_BOTH);
325  if (status)
326  eprintf("nfs41_bind_conn_to_session() failed with %s\n",
328  status = NFS4_OK;
329  }
330  return status;
331 
332 out_err_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) {
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");
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");
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);
401  goto out;
402  }
403  goto out;
404  }
405 
406  status = 0;
407 out:
408  return status;
409 }
#define CreateEvent
Definition: winbase.h:3582
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
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
static int inbuf
Definition: adnsresfilter.c:73
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
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
Definition: dhcpd.h:245
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
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
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:66
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
#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
#define NI_MAXHOST
Definition: ws2def.h:359
SRWLOCK lock
Definition: nfs41.h:169
char * server_name
Definition: widl.c:145
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
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68