1 /* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */ 2 /* $FreeBSD$ */ 3 4 /* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32 33 /* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */ 34 35 /* 36 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 37 * In addition, portions of such source code were derived from Berkeley 38 * 4.3 BSD under license from the Regents of the University of 39 * California. 40 */ 41 42 #if 0 43 #if !defined(lint) && defined(SCCSIDS) 44 static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; 45 #endif 46 #endif 47 48 #ifdef PORTMAP 49 /* 50 * rpc_soc.c 51 * 52 * The backward compatibility routines for the earlier implementation 53 * of RPC, where the only transports supported were tcp/ip and udp/ip. 54 * Based on berkeley socket abstraction, now implemented on the top 55 * of TLI/Streams 56 */ 57 58 #include "namespace.h" 59 #include "reentrant.h" 60 #include <sys/types.h> 61 #include <sys/socket.h> 62 #include <stdio.h> 63 #include <rpc/rpc.h> 64 #include <rpc/pmap_clnt.h> 65 #include <rpc/pmap_prot.h> 66 #include <rpc/nettype.h> 67 #include <syslog.h> 68 #include <netinet/in.h> 69 #include <netdb.h> 70 #include <errno.h> 71 #include <syslog.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <unistd.h> 75 #include "un-namespace.h" 76 77 #include "rpc_com.h" 78 79 extern mutex_t rpcsoc_lock; 80 81 static CLIENT *clnt_com_create __P((struct sockaddr_in *, rpcprog_t, rpcvers_t, 82 int *, u_int, u_int, char *)); 83 static SVCXPRT *svc_com_create __P((int, u_int, u_int, char *)); 84 static bool_t rpc_wrap_bcast __P((char *, struct netbuf *, struct netconfig *)); 85 86 /* XXX */ 87 #define IN4_LOCALHOST_STRING "127.0.0.1" 88 #define IN6_LOCALHOST_STRING "::1" 89 90 /* 91 * A common clnt create routine 92 */ 93 static CLIENT * 94 clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) 95 struct sockaddr_in *raddr; 96 rpcprog_t prog; 97 rpcvers_t vers; 98 int *sockp; 99 u_int sendsz; 100 u_int recvsz; 101 char *tp; 102 { 103 CLIENT *cl; 104 int madefd = FALSE; 105 int fd = *sockp; 106 struct netconfig *nconf; 107 struct netbuf bindaddr; 108 109 mutex_lock(&rpcsoc_lock); 110 if ((nconf = __rpc_getconfip(tp)) == NULL) { 111 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 112 mutex_unlock(&rpcsoc_lock); 113 return (NULL); 114 } 115 if (fd == RPC_ANYSOCK) { 116 fd = __rpc_nconf2fd(nconf); 117 if (fd == -1) 118 goto syserror; 119 madefd = TRUE; 120 } 121 122 if (raddr->sin_port == 0) { 123 u_int proto; 124 u_short sport; 125 126 mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ 127 proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; 128 sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, 129 proto); 130 if (sport == 0) { 131 goto err; 132 } 133 raddr->sin_port = htons(sport); 134 mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ 135 } 136 137 /* Transform sockaddr_in to netbuf */ 138 bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); 139 bindaddr.buf = raddr; 140 141 bindresvport(fd, NULL); 142 cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, 143 sendsz, recvsz); 144 if (cl) { 145 if (madefd == TRUE) { 146 /* 147 * The fd should be closed while destroying the handle. 148 */ 149 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 150 *sockp = fd; 151 } 152 (void) freenetconfigent(nconf); 153 mutex_unlock(&rpcsoc_lock); 154 return (cl); 155 } 156 goto err; 157 158 syserror: 159 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 160 rpc_createerr.cf_error.re_errno = errno; 161 162 err: if (madefd == TRUE) 163 (void)_close(fd); 164 (void) freenetconfigent(nconf); 165 mutex_unlock(&rpcsoc_lock); 166 return (NULL); 167 } 168 169 CLIENT * 170 clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) 171 struct sockaddr_in *raddr; 172 u_long prog; 173 u_long vers; 174 struct timeval wait; 175 int *sockp; 176 u_int sendsz; 177 u_int recvsz; 178 { 179 CLIENT *cl; 180 181 cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 182 sendsz, recvsz, "udp"); 183 if (cl == NULL) { 184 return (NULL); 185 } 186 (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&wait); 187 return (cl); 188 } 189 190 CLIENT * 191 clntudp_create(raddr, program, version, wait, sockp) 192 struct sockaddr_in *raddr; 193 u_long program; 194 u_long version; 195 struct timeval wait; 196 int *sockp; 197 { 198 199 return clntudp_bufcreate(raddr, program, version, wait, sockp, 200 UDPMSGSIZE, UDPMSGSIZE); 201 } 202 203 CLIENT * 204 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 205 struct sockaddr_in *raddr; 206 u_long prog; 207 u_long vers; 208 int *sockp; 209 u_int sendsz; 210 u_int recvsz; 211 { 212 213 return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 214 sendsz, recvsz, "tcp"); 215 } 216 217 CLIENT * 218 clntraw_create(prog, vers) 219 u_long prog; 220 u_long vers; 221 { 222 223 return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); 224 } 225 226 /* 227 * A common server create routine 228 */ 229 static SVCXPRT * 230 svc_com_create(fd, sendsize, recvsize, netid) 231 int fd; 232 u_int sendsize; 233 u_int recvsize; 234 char *netid; 235 { 236 struct netconfig *nconf; 237 SVCXPRT *svc; 238 int madefd = FALSE; 239 int port; 240 struct sockaddr_in sin; 241 242 if ((nconf = __rpc_getconfip(netid)) == NULL) { 243 (void) syslog(LOG_ERR, "Could not get %s transport", netid); 244 return (NULL); 245 } 246 if (fd == RPC_ANYSOCK) { 247 fd = __rpc_nconf2fd(nconf); 248 if (fd == -1) { 249 (void) freenetconfigent(nconf); 250 (void) syslog(LOG_ERR, 251 "svc%s_create: could not open connection", netid); 252 return (NULL); 253 } 254 madefd = TRUE; 255 } 256 257 memset(&sin, 0, sizeof sin); 258 sin.sin_family = AF_INET; 259 bindresvport(fd, &sin); 260 _listen(fd, SOMAXCONN); 261 svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); 262 (void) freenetconfigent(nconf); 263 if (svc == NULL) { 264 if (madefd) 265 (void)_close(fd); 266 return (NULL); 267 } 268 port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); 269 svc->xp_port = ntohs(port); 270 return (svc); 271 } 272 273 SVCXPRT * 274 svctcp_create(fd, sendsize, recvsize) 275 int fd; 276 u_int sendsize; 277 u_int recvsize; 278 { 279 280 return svc_com_create(fd, sendsize, recvsize, "tcp"); 281 } 282 283 SVCXPRT * 284 svcudp_bufcreate(fd, sendsz, recvsz) 285 int fd; 286 u_int sendsz, recvsz; 287 { 288 289 return svc_com_create(fd, sendsz, recvsz, "udp"); 290 } 291 292 SVCXPRT * 293 svcfd_create(fd, sendsize, recvsize) 294 int fd; 295 u_int sendsize; 296 u_int recvsize; 297 { 298 299 return svc_fd_create(fd, sendsize, recvsize); 300 } 301 302 303 SVCXPRT * 304 svcudp_create(fd) 305 int fd; 306 { 307 308 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); 309 } 310 311 SVCXPRT * 312 svcraw_create() 313 { 314 315 return svc_raw_create(); 316 } 317 318 int 319 get_myaddress(addr) 320 struct sockaddr_in *addr; 321 { 322 323 memset((void *) addr, 0, sizeof(*addr)); 324 addr->sin_family = AF_INET; 325 addr->sin_port = htons(PMAPPORT); 326 addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 327 return (0); 328 } 329 330 /* 331 * For connectionless "udp" transport. Obsoleted by rpc_call(). 332 */ 333 int 334 callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) 335 char *host; 336 int prognum, versnum, procnum; 337 xdrproc_t inproc, outproc; 338 void *in, *out; 339 { 340 341 return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, 342 (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); 343 } 344 345 /* 346 * For connectionless kind of transport. Obsoleted by rpc_reg() 347 */ 348 int 349 registerrpc(prognum, versnum, procnum, progname, inproc, outproc) 350 int prognum, versnum, procnum; 351 char *(*progname) __P((char [UDPMSGSIZE])); 352 xdrproc_t inproc, outproc; 353 { 354 355 return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, 356 (rpcproc_t)procnum, progname, inproc, outproc, "udp"); 357 } 358 359 /* 360 * All the following clnt_broadcast stuff is convulated; it supports 361 * the earlier calling style of the callback function 362 */ 363 static thread_key_t clnt_broadcast_key; 364 static resultproc_t clnt_broadcast_result_main; 365 366 /* 367 * Need to translate the netbuf address into sockaddr_in address. 368 * Dont care about netid here. 369 */ 370 /* ARGSUSED */ 371 static bool_t 372 rpc_wrap_bcast(resultp, addr, nconf) 373 char *resultp; /* results of the call */ 374 struct netbuf *addr; /* address of the guy who responded */ 375 struct netconfig *nconf; /* Netconf of the transport */ 376 { 377 resultproc_t clnt_broadcast_result; 378 379 if (strcmp(nconf->nc_netid, "udp")) 380 return (FALSE); 381 if (thr_main()) 382 clnt_broadcast_result = clnt_broadcast_result_main; 383 else 384 clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key); 385 return (*clnt_broadcast_result)(resultp, 386 (struct sockaddr_in *)addr->buf); 387 } 388 389 /* 390 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). 391 */ 392 enum clnt_stat 393 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 394 u_long prog; /* program number */ 395 u_long vers; /* version number */ 396 u_long proc; /* procedure number */ 397 xdrproc_t xargs; /* xdr routine for args */ 398 caddr_t argsp; /* pointer to args */ 399 xdrproc_t xresults; /* xdr routine for results */ 400 caddr_t resultsp; /* pointer to results */ 401 resultproc_t eachresult; /* call with each result obtained */ 402 { 403 extern mutex_t tsd_lock; 404 405 if (thr_main()) 406 clnt_broadcast_result_main = eachresult; 407 else { 408 if (clnt_broadcast_key == 0) { 409 mutex_lock(&tsd_lock); 410 if (clnt_broadcast_key == 0) 411 thr_keycreate(&clnt_broadcast_key, free); 412 mutex_unlock(&tsd_lock); 413 } 414 thr_setspecific(clnt_broadcast_key, (void *) eachresult); 415 } 416 return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, 417 (rpcproc_t)proc, xargs, argsp, xresults, resultsp, 418 (resultproc_t) rpc_wrap_bcast, "udp"); 419 } 420 421 /* 422 * Create the client des authentication object. Obsoleted by 423 * authdes_seccreate(). 424 */ 425 AUTH * 426 authdes_create(servername, window, syncaddr, ckey) 427 char *servername; /* network name of server */ 428 u_int window; /* time to live */ 429 struct sockaddr *syncaddr; /* optional hostaddr to sync with */ 430 des_block *ckey; /* optional conversation key to use */ 431 { 432 AUTH *dummy; 433 AUTH *nauth; 434 char hostname[NI_MAXHOST]; 435 436 if (syncaddr) { 437 /* 438 * Change addr to hostname, because that is the way 439 * new interface takes it. 440 */ 441 if (getnameinfo(syncaddr, syncaddr->sa_len, hostname, 442 sizeof hostname, NULL, 0, 0) != 0) 443 goto fallback; 444 445 nauth = authdes_seccreate(servername, window, hostname, ckey); 446 return (nauth); 447 } 448 fallback: 449 dummy = authdes_seccreate(servername, window, NULL, ckey); 450 return (dummy); 451 } 452 453 #endif /* PORTMAP */ 454