1 /* 2 * Copyright (c) 2009, Sun Microsystems, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of Sun Microsystems, Inc. nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. 31 * All rights reserved. 32 */ 33 34 /* NFSv4.1 client for Windows 35 * Copyright � 2012 The Regents of the University of Michigan 36 * 37 * Olga Kornievskaia <aglo@umich.edu> 38 * Casey Bodley <cbodley@umich.edu> 39 * 40 * This library is free software; you can redistribute it and/or modify it 41 * under the terms of the GNU Lesser General Public License as published by 42 * the Free Software Foundation; either version 2.1 of the License, or (at 43 * your option) any later version. 44 * 45 * This library is distributed in the hope that it will be useful, but 46 * without any warranty; without even the implied warranty of merchantability 47 * or fitness for a particular purpose. See the GNU Lesser General Public 48 * License for more details. 49 * 50 * You should have received a copy of the GNU Lesser General Public License 51 * along with this library; if not, write to the Free Software Foundation, 52 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 53 */ 54 55 #include <wintirpc.h> 56 //#include <pthread.h> 57 #include <reentrant.h> 58 #include <sys/types.h> 59 //#include <sys/fcntl.h> 60 #include <fcntl.h> 61 //#include <sys/socket.h> 62 //#include <netinet/in.h> 63 //#include <netinet/tcp.h> 64 #include <stdio.h> 65 #include <errno.h> 66 #include <string.h> 67 #include <stdlib.h> 68 //#include <netdb.h> 69 //#include <syslog.h> 70 #include <rpc/rpc.h> 71 #include <rpc/nettype.h> 72 //#include <unistd.h> 73 #include "rpc_com.h" 74 75 extern bool_t __rpc_is_local_host(const char *); 76 #if 0 /* WINDOWS */ 77 int __rpc_raise_fd(int); 78 #endif 79 80 #ifndef NETIDLEN 81 #define NETIDLEN 32 82 #endif 83 84 /* 85 * Generic client creation with version checking the value of 86 * vers_out is set to the highest server supported value 87 * vers_low <= vers_out <= vers_high AND an error results 88 * if this can not be done. 89 * 90 * It calls clnt_create_vers_timed() with a NULL value for the timeout 91 * pointer, which indicates that the default timeout should be used. 92 */ 93 CLIENT * 94 clnt_create_vers(const char *hostname, const rpcprog_t prog, rpcvers_t *vers_out, 95 const rpcvers_t vers_low, const rpcvers_t vers_high, const char *nettype) 96 { 97 98 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, 99 vers_high, nettype, NULL)); 100 } 101 102 /* 103 * This the routine has the same definition as clnt_create_vers(), 104 * except it takes an additional timeout parameter - a pointer to 105 * a timeval structure. A NULL value for the pointer indicates 106 * that the default timeout value should be used. 107 */ 108 CLIENT * 109 clnt_create_vers_timed(const char *hostname, const rpcprog_t prog, 110 rpcvers_t *vers_out, const rpcvers_t vers_low_in, const rpcvers_t vers_high_in, 111 const char *nettype, const struct timeval *tp) 112 { 113 CLIENT *clnt; 114 struct timeval to; 115 enum clnt_stat rpc_stat; 116 struct rpc_err rpcerr; 117 rpcvers_t vers_high = vers_high_in; 118 rpcvers_t vers_low = vers_low_in; 119 120 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); 121 if (clnt == NULL) { 122 return (NULL); 123 } 124 to.tv_sec = 10; 125 to.tv_usec = 0; 126 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 127 (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); 128 if (rpc_stat == RPC_SUCCESS) { 129 *vers_out = vers_high; 130 return (clnt); 131 } 132 while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { 133 unsigned int minvers, maxvers; 134 135 clnt_geterr(clnt, &rpcerr); 136 minvers = rpcerr.re_vers.low; 137 maxvers = rpcerr.re_vers.high; 138 if (maxvers < vers_high) 139 vers_high = maxvers; 140 else 141 vers_high--; 142 if (minvers > vers_low) 143 vers_low = minvers; 144 if (vers_low > vers_high) { 145 goto error; 146 } 147 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); 148 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 149 (char *)NULL, (xdrproc_t)xdr_void, 150 (char *)NULL, to); 151 if (rpc_stat == RPC_SUCCESS) { 152 *vers_out = vers_high; 153 return (clnt); 154 } 155 } 156 clnt_geterr(clnt, &rpcerr); 157 158 error: 159 rpc_createerr.cf_stat = rpc_stat; 160 rpc_createerr.cf_error = rpcerr; 161 clnt_destroy(clnt); 162 return (NULL); 163 } 164 165 /* 166 * Top level client creation routine. 167 * Generic client creation: takes (servers name, program-number, nettype) and 168 * returns client handle. Default options are set, which the user can 169 * change using the rpc equivalent of _ioctl()'s. 170 * 171 * It tries for all the netids in that particular class of netid until 172 * it succeeds. 173 * XXX The error message in the case of failure will be the one 174 * pertaining to the last create error. 175 * 176 * It calls clnt_create_timed() with the default timeout. 177 */ 178 CLIENT * 179 clnt_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 180 const char *nettype) 181 { 182 183 return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); 184 } 185 186 /* 187 * This the routine has the same definition as clnt_create(), 188 * except it takes an additional timeout parameter - a pointer to 189 * a timeval structure. A NULL value for the pointer indicates 190 * that the default timeout value should be used. 191 * 192 * This function calls clnt_tp_create_timed(). 193 */ 194 CLIENT * 195 clnt_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 196 const char *netclass, const struct timeval *tp) 197 { 198 struct netconfig *nconf; 199 CLIENT *clnt = NULL; 200 void *handle; 201 enum clnt_stat save_cf_stat = RPC_SUCCESS; 202 struct rpc_err save_cf_error; 203 char nettype_array[NETIDLEN]; 204 char *nettype = &nettype_array[0]; 205 206 if (netclass == NULL) 207 nettype = NULL; 208 else { 209 size_t len = strlen(netclass); 210 if (len >= sizeof (nettype_array)) { 211 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 212 return (NULL); 213 } 214 strcpy(nettype, netclass); 215 } 216 217 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 218 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 219 return (NULL); 220 } 221 rpc_createerr.cf_stat = RPC_SUCCESS; 222 while (clnt == NULL) { 223 if ((nconf = __rpc_getconf(handle)) == NULL) { 224 if (rpc_createerr.cf_stat == RPC_SUCCESS) 225 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 226 break; 227 } 228 #ifdef CLNT_DEBUG 229 printf("trying netid %s\n", nconf->nc_netid); 230 #endif 231 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); 232 if (clnt) 233 break; 234 else { 235 /* 236 * Since we didn't get a name-to-address 237 * translation failure here, we remember 238 * this particular error. The object of 239 * this is to enable us to return to the 240 * caller a more-specific error than the 241 * unhelpful ``Name to address translation 242 * failed'' which might well occur if we 243 * merely returned the last error (because 244 * the local loopbacks are typically the 245 * last ones in /etc/netconfig and the most 246 * likely to be unable to translate a host 247 * name). We also check for a more 248 * meaningful error than ``unknown host 249 * name'' for the same reasons. 250 */ 251 if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && 252 rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { 253 save_cf_stat = rpc_createerr.cf_stat; 254 save_cf_error = rpc_createerr.cf_error; 255 } 256 } 257 } 258 259 /* 260 * Attempt to return an error more specific than ``Name to address 261 * translation failed'' or ``unknown host name'' 262 */ 263 if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || 264 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && 265 (save_cf_stat != RPC_SUCCESS)) { 266 rpc_createerr.cf_stat = save_cf_stat; 267 rpc_createerr.cf_error = save_cf_error; 268 } 269 __rpc_endconf(handle); 270 return (clnt); 271 } 272 273 /* 274 * Generic client creation: takes (servers name, program-number, netconf) and 275 * returns client handle. Default options are set, which the user can 276 * change using the rpc equivalent of _ioctl()'s : clnt_control() 277 * It finds out the server address from rpcbind and calls clnt_tli_create(). 278 * 279 * It calls clnt_tp_create_timed() with the default timeout. 280 */ 281 CLIENT * 282 clnt_tp_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 283 const struct netconfig *nconf) 284 { 285 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); 286 } 287 288 /* 289 * This has the same definition as clnt_tp_create(), except it 290 * takes an additional parameter - a pointer to a timeval structure. 291 * A NULL value for the timeout pointer indicates that the default 292 * value for the timeout should be used. 293 */ 294 CLIENT * 295 clnt_tp_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 296 const struct netconfig *nconf, const struct timeval *tp) 297 { 298 struct netbuf *svcaddr; /* servers address */ 299 CLIENT *cl = NULL; /* client handle */ 300 301 if (nconf == NULL) { 302 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 303 return (NULL); 304 } 305 306 /* 307 * Get the address of the server 308 */ 309 if ((svcaddr = __rpcb_findaddr_timed(prog, vers, 310 (struct netconfig *)nconf, (char *)hostname, 311 &cl, (struct timeval *)tp)) == NULL) { 312 /* appropriate error number is set by rpcbind libraries */ 313 return (NULL); 314 } 315 if (cl == NULL) { 316 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 317 prog, vers, 0, 0, NULL, NULL, NULL); 318 } else { 319 /* Reuse the CLIENT handle and change the appropriate fields */ 320 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 321 if (cl->cl_netid == NULL) 322 cl->cl_netid = strdup(nconf->nc_netid); 323 if (cl->cl_tp == NULL) 324 cl->cl_tp = strdup(nconf->nc_device); 325 (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 326 (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 327 } else { 328 CLNT_DESTROY(cl); 329 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 330 prog, vers, 0, 0, NULL, NULL, NULL); 331 } 332 } 333 free(svcaddr->buf); 334 free(svcaddr); 335 return (cl); 336 } 337 338 /* 339 * Generic client creation: returns client handle. 340 * Default options are set, which the user can 341 * change using the rpc equivalent of _ioctl()'s : clnt_control(). 342 * If fd is RPC_ANYFD, it will be opened using nconf. 343 * It will be bound if not so. 344 * If sizes are 0; appropriate defaults will be chosen. 345 */ 346 CLIENT * 347 clnt_tli_create(const SOCKET fd_in, const struct netconfig *nconf, 348 struct netbuf *svcaddr, const rpcprog_t prog, const rpcvers_t vers, 349 const uint sendsz, const uint recvsz, 350 int (*callback_xdr)(void *, void *), 351 int (*callback_function)(void *, void *, void **), 352 void *callback_args) 353 { 354 CLIENT *cl; /* client handle */ 355 bool_t madefd = FALSE; /* whether fd opened here */ 356 long servtype; 357 BOOL one = TRUE; 358 struct __rpc_sockinfo si; 359 extern int __rpc_minfd; 360 SOCKET fd = fd_in; 361 362 if (fd == RPC_ANYFD) { 363 if (nconf == NULL) { 364 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 365 return (NULL); 366 } 367 368 fd = __rpc_nconf2fd(nconf); 369 370 if (fd == INVALID_SOCKET) 371 goto err; 372 #if 0 373 if (fd < __rpc_minfd) 374 fd = __rpc_raise_fd(fd); 375 #endif 376 madefd = TRUE; 377 servtype = nconf->nc_semantics; 378 bindresvport(fd, NULL); 379 if (!__rpc_fd2sockinfo(fd, &si)) 380 goto err; 381 } else { 382 if (!__rpc_fd2sockinfo(fd, &si)) 383 goto err; 384 servtype = __rpc_socktype2seman(si.si_socktype); 385 if (servtype == -1) { 386 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 387 return (NULL); 388 } 389 } 390 391 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { 392 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ 393 goto err1; 394 } 395 396 switch (servtype) { 397 case NC_TPI_COTS: 398 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz, 399 callback_xdr, callback_function, callback_args); 400 break; 401 case NC_TPI_COTS_ORD: 402 if (nconf && 403 ((strcmp(nconf->nc_protofmly, "inet") == 0) || 404 (strcmp(nconf->nc_protofmly, "inet6") == 0))) { 405 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, 406 sizeof (one)); 407 } 408 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz, 409 callback_xdr, callback_function, callback_args); 410 break; 411 case NC_TPI_CLTS: 412 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 413 break; 414 default: 415 goto err; 416 } 417 418 if (cl == NULL) 419 goto err1; /* borrow errors from clnt_dg/vc creates */ 420 if (nconf) { 421 cl->cl_netid = strdup(nconf->nc_netid); 422 cl->cl_tp = strdup(nconf->nc_device); 423 } else { 424 cl->cl_netid = ""; 425 cl->cl_tp = ""; 426 } 427 if (madefd) { 428 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 429 /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ 430 }; 431 432 return (cl); 433 434 err: 435 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 436 rpc_createerr.cf_error.re_errno = errno; 437 err1: if (madefd) 438 (void)closesocket(fd); 439 return (NULL); 440 } 441 442 #if 0 /* WINDOWS */ 443 /* 444 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), 445 * we try to not use them. The __rpc_raise_fd() routine will dup 446 * a descriptor to a higher value. If we fail to do it, we continue 447 * to use the old one (and hope for the best). 448 */ 449 int __rpc_minfd = 3; 450 451 int 452 __rpc_raise_fd(int fd) 453 { 454 int nfd; 455 456 if (fd >= __rpc_minfd) 457 return (fd); 458 459 if ((nfd = fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) 460 return (fd); 461 462 if (fsync(nfd) == -1) { 463 closesocket(nfd); 464 return (fd); 465 } 466 467 if (closesocket(fd) == -1) { 468 /* this is okay, we will syslog an error, then use the new fd */ 469 (void) syslog(LOG_ERR, 470 "could not close() fd %d; mem & fd leak", fd); 471 } 472 473 return (nfd); 474 } 475 #endif 476