svc_vc.c revision 90272
1/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2/* $FreeBSD: head/lib/libc/rpc/svc_vc.c 90272 2002-02-05 23:46:37Z alfred $ */ 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#include <sys/cdefs.h> 34#if defined(LIBC_SCCS) && !defined(lint) 35static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 36static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 37#endif 38 39/* 40 * svc_vc.c, Server side for Connection Oriented based RPC. 41 * 42 * Actually implements two flavors of transporter - 43 * a tcp rendezvouser (a listner and connection establisher) 44 * and a record/tcp stream. 45 */ 46 47#include "namespace.h" 48#include "reentrant.h" 49#include <sys/types.h> 50#include <sys/param.h> 51#include <sys/poll.h> 52#include <sys/socket.h> 53#include <sys/un.h> 54#include <sys/uio.h> 55#include <netinet/in.h> 56#include <netinet/tcp.h> 57 58#include <assert.h> 59#include <err.h> 60#include <errno.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <unistd.h> 65 66#include <rpc/rpc.h> 67 68#include "rpc_com.h" 69#include "un-namespace.h" 70 71struct cmessage { 72 struct cmsghdr cmsg; 73 struct cmsgcred cmcred; 74}; 75 76static SVCXPRT *makefd_xprt __P((int, u_int, u_int)); 77static bool_t rendezvous_request __P((SVCXPRT *, struct rpc_msg *)); 78static enum xprt_stat rendezvous_stat __P((SVCXPRT *)); 79static void svc_vc_destroy __P((SVCXPRT *)); 80static int read_vc __P((caddr_t, caddr_t, int)); 81static int write_vc __P((caddr_t, caddr_t, int)); 82static enum xprt_stat svc_vc_stat __P((SVCXPRT *)); 83static bool_t svc_vc_recv __P((SVCXPRT *, struct rpc_msg *)); 84static bool_t svc_vc_getargs __P((SVCXPRT *, xdrproc_t, caddr_t)); 85static bool_t svc_vc_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t)); 86static bool_t svc_vc_reply __P((SVCXPRT *, struct rpc_msg *)); 87static void svc_vc_rendezvous_ops __P((SVCXPRT *)); 88static void svc_vc_ops __P((SVCXPRT *)); 89static bool_t svc_vc_control __P((SVCXPRT *xprt, const u_int rq, void *in)); 90static int __msgread_withcred(int, void *, size_t, struct cmessage *); 91static int __msgwrite(int, void *, size_t); 92 93struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 94 u_int sendsize; 95 u_int recvsize; 96}; 97 98struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 99 enum xprt_stat strm_stat; 100 u_int32_t x_id; 101 XDR xdrs; 102 char verf_body[MAX_AUTH_BYTES]; 103}; 104 105/* 106 * Usage: 107 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 108 * 109 * Creates, registers, and returns a (rpc) tcp based transporter. 110 * Once *xprt is initialized, it is registered as a transporter 111 * see (svc.h, xprt_register). This routine returns 112 * a NULL if a problem occurred. 113 * 114 * The filedescriptor passed in is expected to refer to a bound, but 115 * not yet connected socket. 116 * 117 * Since streams do buffered io similar to stdio, the caller can specify 118 * how big the send and receive buffers are via the second and third parms; 119 * 0 => use the system default. 120 */ 121SVCXPRT * 122svc_vc_create(fd, sendsize, recvsize) 123 int fd; 124 u_int sendsize; 125 u_int recvsize; 126{ 127 SVCXPRT *xprt; 128 struct cf_rendezvous *r = NULL; 129 struct __rpc_sockinfo si; 130 struct sockaddr_storage sslocal; 131 socklen_t slen; 132 133 r = mem_alloc(sizeof(*r)); 134 if (r == NULL) { 135 warnx("svc_vc_create: out of memory"); 136 goto cleanup_svc_vc_create; 137 } 138 if (!__rpc_fd2sockinfo(fd, &si)) 139 return NULL; 140 r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 141 r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 142 xprt = mem_alloc(sizeof(SVCXPRT)); 143 if (xprt == NULL) { 144 warnx("svc_vc_create: out of memory"); 145 goto cleanup_svc_vc_create; 146 } 147 xprt->xp_tp = NULL; 148 xprt->xp_p1 = (caddr_t)(void *)r; 149 xprt->xp_p2 = NULL; 150 xprt->xp_p3 = NULL; 151 xprt->xp_verf = _null_auth; 152 svc_vc_rendezvous_ops(xprt); 153 xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 154 xprt->xp_fd = fd; 155 156 slen = sizeof (struct sockaddr_storage); 157 if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 158 warnx("svc_vc_create: could not retrieve local addr"); 159 goto cleanup_svc_vc_create; 160 } 161 162 xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 163 xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 164 if (xprt->xp_ltaddr.buf == NULL) { 165 warnx("svc_vc_create: no mem for local addr"); 166 goto cleanup_svc_vc_create; 167 } 168 memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 169 170 xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 171 xprt_register(xprt); 172 return (xprt); 173cleanup_svc_vc_create: 174 if (r != NULL) 175 mem_free(r, sizeof(*r)); 176 return (NULL); 177} 178 179/* 180 * Like svtcp_create(), except the routine takes any *open* UNIX file 181 * descriptor as its first input. 182 */ 183SVCXPRT * 184svc_fd_create(fd, sendsize, recvsize) 185 int fd; 186 u_int sendsize; 187 u_int recvsize; 188{ 189 struct sockaddr_storage ss; 190 socklen_t slen; 191 SVCXPRT *ret; 192 193 assert(fd != -1); 194 195 ret = makefd_xprt(fd, sendsize, recvsize); 196 if (ret == NULL) 197 return NULL; 198 199 slen = sizeof (struct sockaddr_storage); 200 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 201 warnx("svc_fd_create: could not retrieve local addr"); 202 goto freedata; 203 } 204 ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 205 ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 206 if (ret->xp_ltaddr.buf == NULL) { 207 warnx("svc_fd_create: no mem for local addr"); 208 goto freedata; 209 } 210 memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 211 212 slen = sizeof (struct sockaddr_storage); 213 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 214 warnx("svc_fd_create: could not retrieve remote addr"); 215 goto freedata; 216 } 217 ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 218 ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 219 if (ret->xp_rtaddr.buf == NULL) { 220 warnx("svc_fd_create: no mem for local addr"); 221 goto freedata; 222 } 223 memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 224#ifdef PORTMAP 225 if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 226 ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 227 ret->xp_addrlen = sizeof (struct sockaddr_in); 228 } 229#endif /* PORTMAP */ 230 231 return ret; 232 233freedata: 234 if (ret->xp_ltaddr.buf != NULL) 235 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 236 237 return NULL; 238} 239 240static SVCXPRT * 241makefd_xprt(fd, sendsize, recvsize) 242 int fd; 243 u_int sendsize; 244 u_int recvsize; 245{ 246 SVCXPRT *xprt; 247 struct cf_conn *cd; 248 const char *netid; 249 struct __rpc_sockinfo si; 250 251 assert(fd != -1); 252 253 xprt = mem_alloc(sizeof(SVCXPRT)); 254 if (xprt == NULL) { 255 warnx("svc_vc: makefd_xprt: out of memory"); 256 goto done; 257 } 258 memset(xprt, 0, sizeof *xprt); 259 cd = mem_alloc(sizeof(struct cf_conn)); 260 if (cd == NULL) { 261 warnx("svc_tcp: makefd_xprt: out of memory"); 262 mem_free(xprt, sizeof(SVCXPRT)); 263 xprt = NULL; 264 goto done; 265 } 266 cd->strm_stat = XPRT_IDLE; 267 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 268 (caddr_t)(void *)xprt, read_vc, write_vc); 269 xprt->xp_p1 = (caddr_t)(void *)cd; 270 xprt->xp_verf.oa_base = cd->verf_body; 271 svc_vc_ops(xprt); /* truely deals with calls */ 272 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 273 xprt->xp_fd = fd; 274 if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 275 xprt->xp_netid = strdup(netid); 276 277 xprt_register(xprt); 278done: 279 return (xprt); 280} 281 282/*ARGSUSED*/ 283static bool_t 284rendezvous_request(xprt, msg) 285 SVCXPRT *xprt; 286 struct rpc_msg *msg; 287{ 288 int sock; 289 struct cf_rendezvous *r; 290 struct sockaddr_storage addr; 291 socklen_t len; 292 struct __rpc_sockinfo si; 293 294 assert(xprt != NULL); 295 assert(msg != NULL); 296 297 r = (struct cf_rendezvous *)xprt->xp_p1; 298again: 299 len = sizeof addr; 300 if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 301 &len)) < 0) { 302 if (errno == EINTR) 303 goto again; 304 return (FALSE); 305 } 306 /* 307 * make a new transporter (re-uses xprt) 308 */ 309 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 310 xprt->xp_rtaddr.buf = mem_alloc(len); 311 if (xprt->xp_rtaddr.buf == NULL) 312 return (FALSE); 313 memcpy(xprt->xp_rtaddr.buf, &addr, len); 314 xprt->xp_rtaddr.len = len; 315 if (addr.ss_family == AF_LOCAL) { 316 xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; 317 xprt->xp_addrlen = sizeof (struct sockaddr_in); 318 } 319#ifdef PORTMAP 320 if (addr.ss_family == AF_INET) { 321 xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; 322 xprt->xp_addrlen = sizeof (struct sockaddr_in); 323 } 324#endif /* PORTMAP */ 325 if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 326 len = 1; 327 /* XXX fvdl - is this useful? */ 328 _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 329 } 330 return (FALSE); /* there is never an rpc msg to be processed */ 331} 332 333/*ARGSUSED*/ 334static enum xprt_stat 335rendezvous_stat(xprt) 336 SVCXPRT *xprt; 337{ 338 339 return (XPRT_IDLE); 340} 341 342static void 343svc_vc_destroy(xprt) 344 SVCXPRT *xprt; 345{ 346 struct cf_conn *cd; 347 struct cf_rendezvous *r; 348 349 assert(xprt != NULL); 350 351 cd = (struct cf_conn *)xprt->xp_p1; 352 353 xprt_unregister(xprt); 354 if (xprt->xp_fd != RPC_ANYFD) 355 (void)_close(xprt->xp_fd); 356 if (xprt->xp_port != 0) { 357 /* a rendezvouser socket */ 358 r = (struct cf_rendezvous *)xprt->xp_p1; 359 mem_free(r, sizeof (struct cf_rendezvous)); 360 xprt->xp_port = 0; 361 } else { 362 /* an actual connection socket */ 363 XDR_DESTROY(&(cd->xdrs)); 364 mem_free(cd, sizeof(struct cf_conn)); 365 } 366 if (xprt->xp_rtaddr.buf) 367 mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 368 if (xprt->xp_ltaddr.buf) 369 mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 370 if (xprt->xp_tp) 371 free(xprt->xp_tp); 372 if (xprt->xp_netid) 373 free(xprt->xp_netid); 374 mem_free(xprt, sizeof(SVCXPRT)); 375} 376 377/*ARGSUSED*/ 378static bool_t 379svc_vc_control(xprt, rq, in) 380 SVCXPRT *xprt; 381 const u_int rq; 382 void *in; 383{ 384 return (FALSE); 385} 386 387/* 388 * reads data from the tcp or uip connection. 389 * any error is fatal and the connection is closed. 390 * (And a read of zero bytes is a half closed stream => error.) 391 * All read operations timeout after 35 seconds. A timeout is 392 * fatal for the connection. 393 */ 394static int 395read_vc(xprtp, buf, len) 396 caddr_t xprtp; 397 caddr_t buf; 398 int len; 399{ 400 SVCXPRT *xprt; 401 int sock; 402 int milliseconds = 35 * 1000; 403 struct pollfd pollfd; 404 struct sockaddr *sa; 405 struct cmessage *cm; 406 407 xprt = (SVCXPRT *)(void *)xprtp; 408 assert(xprt != NULL); 409 410 sock = xprt->xp_fd; 411 412 do { 413 pollfd.fd = sock; 414 pollfd.events = POLLIN; 415 pollfd.revents = 0; 416 switch (_poll(&pollfd, 1, milliseconds)) { 417 case -1: 418 if (errno == EINTR) 419 continue; 420 /*FALLTHROUGH*/ 421 case 0: 422 goto fatal_err; 423 424 default: 425 break; 426 } 427 } while ((pollfd.revents & POLLIN) == 0); 428 429 cm = NULL; 430 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 431 if (sa->sa_family == AF_LOCAL) { 432 cm = (struct cmessage *)xprt->xp_verf.oa_base; 433 if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) { 434 xprt->xp_p2 = &cm->cmcred; 435 return (len); 436 } else 437 goto fatal_err; 438 } else { 439 if ((len = _read(sock, buf, (size_t)len)) > 0) 440 return (len); 441 } 442 443fatal_err: 444 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 445 return (-1); 446} 447 448/* 449 * writes data to the tcp connection. 450 * Any error is fatal and the connection is closed. 451 */ 452static int 453write_vc(xprtp, buf, len) 454 caddr_t xprtp; 455 caddr_t buf; 456 int len; 457{ 458 SVCXPRT *xprt; 459 int i, cnt; 460 struct sockaddr *sa; 461 462 xprt = (SVCXPRT *)(void *)xprtp; 463 assert(xprt != NULL); 464 465 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 466 if (sa->sa_family == AF_LOCAL) { 467 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 468 if ((i = __msgwrite(xprt->xp_fd, buf, 469 (size_t)cnt)) < 0) { 470 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = 471 XPRT_DIED; 472 return (-1); 473 } 474 } 475 } else { 476 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 477 if ((i = _write(xprt->xp_fd, buf, 478 (size_t)cnt)) < 0) { 479 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = 480 XPRT_DIED; 481 return (-1); 482 } 483 } 484 } 485 486 return (len); 487} 488 489static enum xprt_stat 490svc_vc_stat(xprt) 491 SVCXPRT *xprt; 492{ 493 struct cf_conn *cd; 494 495 assert(xprt != NULL); 496 497 cd = (struct cf_conn *)(xprt->xp_p1); 498 499 if (cd->strm_stat == XPRT_DIED) 500 return (XPRT_DIED); 501 if (! xdrrec_eof(&(cd->xdrs))) 502 return (XPRT_MOREREQS); 503 return (XPRT_IDLE); 504} 505 506static bool_t 507svc_vc_recv(xprt, msg) 508 SVCXPRT *xprt; 509 struct rpc_msg *msg; 510{ 511 struct cf_conn *cd; 512 XDR *xdrs; 513 514 assert(xprt != NULL); 515 assert(msg != NULL); 516 517 cd = (struct cf_conn *)(xprt->xp_p1); 518 xdrs = &(cd->xdrs); 519 520 xdrs->x_op = XDR_DECODE; 521 (void)xdrrec_skiprecord(xdrs); 522 if (xdr_callmsg(xdrs, msg)) { 523 cd->x_id = msg->rm_xid; 524 return (TRUE); 525 } 526 cd->strm_stat = XPRT_DIED; 527 return (FALSE); 528} 529 530static bool_t 531svc_vc_getargs(xprt, xdr_args, args_ptr) 532 SVCXPRT *xprt; 533 xdrproc_t xdr_args; 534 caddr_t args_ptr; 535{ 536 537 assert(xprt != NULL); 538 /* args_ptr may be NULL */ 539 return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 540 args_ptr)); 541} 542 543static bool_t 544svc_vc_freeargs(xprt, xdr_args, args_ptr) 545 SVCXPRT *xprt; 546 xdrproc_t xdr_args; 547 caddr_t args_ptr; 548{ 549 XDR *xdrs; 550 551 assert(xprt != NULL); 552 /* args_ptr may be NULL */ 553 554 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 555 556 xdrs->x_op = XDR_FREE; 557 return ((*xdr_args)(xdrs, args_ptr)); 558} 559 560static bool_t 561svc_vc_reply(xprt, msg) 562 SVCXPRT *xprt; 563 struct rpc_msg *msg; 564{ 565 struct cf_conn *cd; 566 XDR *xdrs; 567 bool_t stat; 568 569 assert(xprt != NULL); 570 assert(msg != NULL); 571 572 cd = (struct cf_conn *)(xprt->xp_p1); 573 xdrs = &(cd->xdrs); 574 575 xdrs->x_op = XDR_ENCODE; 576 msg->rm_xid = cd->x_id; 577 stat = xdr_replymsg(xdrs, msg); 578 (void)xdrrec_endofrecord(xdrs, TRUE); 579 return (stat); 580} 581 582static void 583svc_vc_ops(xprt) 584 SVCXPRT *xprt; 585{ 586 static struct xp_ops ops; 587 static struct xp_ops2 ops2; 588 extern mutex_t ops_lock; 589 590/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 591 592 mutex_lock(&ops_lock); 593 if (ops.xp_recv == NULL) { 594 ops.xp_recv = svc_vc_recv; 595 ops.xp_stat = svc_vc_stat; 596 ops.xp_getargs = svc_vc_getargs; 597 ops.xp_reply = svc_vc_reply; 598 ops.xp_freeargs = svc_vc_freeargs; 599 ops.xp_destroy = svc_vc_destroy; 600 ops2.xp_control = svc_vc_control; 601 } 602 xprt->xp_ops = &ops; 603 xprt->xp_ops2 = &ops2; 604 mutex_unlock(&ops_lock); 605} 606 607static void 608svc_vc_rendezvous_ops(xprt) 609 SVCXPRT *xprt; 610{ 611 static struct xp_ops ops; 612 static struct xp_ops2 ops2; 613 extern mutex_t ops_lock; 614 615 mutex_lock(&ops_lock); 616 if (ops.xp_recv == NULL) { 617 ops.xp_recv = rendezvous_request; 618 ops.xp_stat = rendezvous_stat; 619 ops.xp_getargs = 620 (bool_t (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort; 621 ops.xp_reply = 622 (bool_t (*) __P((SVCXPRT *, struct rpc_msg *)))abort; 623 ops.xp_freeargs = 624 (bool_t (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort, 625 ops.xp_destroy = svc_vc_destroy; 626 ops2.xp_control = svc_vc_control; 627 } 628 xprt->xp_ops = &ops; 629 xprt->xp_ops2 = &ops2; 630 mutex_unlock(&ops_lock); 631} 632 633int 634__msgread_withcred(sock, buf, cnt, cmp) 635 int sock; 636 void *buf; 637 size_t cnt; 638 struct cmessage *cmp; 639{ 640 struct iovec iov[1]; 641 struct msghdr msg; 642 union { 643 struct cmsghdr cmsg; 644 char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 645 } cm; 646 int ret; 647 648 649 bzero(&cm, sizeof(cm)); 650 iov[0].iov_base = buf; 651 iov[0].iov_len = cnt; 652 653 msg.msg_iov = iov; 654 msg.msg_iovlen = 1; 655 msg.msg_name = NULL; 656 msg.msg_namelen = 0; 657 msg.msg_control = &cm; 658 msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 659 msg.msg_flags = 0; 660 661 ret = _recvmsg(sock, &msg, 0); 662 bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg)); 663 bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred)); 664 665 if (msg.msg_controllen == 0 || 666 (msg.msg_flags & MSG_CTRUNC) != 0) 667 return (-1); 668 669 return (ret); 670} 671 672static int 673__msgwrite(sock, buf, cnt) 674 int sock; 675 void *buf; 676 size_t cnt; 677{ 678 struct iovec iov[1]; 679 struct msghdr msg; 680 struct cmessage cm; 681 682 bzero((char *)&cm, sizeof(cm)); 683 iov[0].iov_base = buf; 684 iov[0].iov_len = cnt; 685 686 cm.cmsg.cmsg_type = SCM_CREDS; 687 cm.cmsg.cmsg_level = SOL_SOCKET; 688 cm.cmsg.cmsg_len = sizeof(struct cmessage); 689 690 msg.msg_iov = iov; 691 msg.msg_iovlen = 1; 692 msg.msg_name = NULL; 693 msg.msg_namelen = 0; 694 msg.msg_control = (caddr_t)&cm; 695 msg.msg_controllen = sizeof(struct cmessage); 696 msg.msg_flags = 0; 697 698 return(_sendmsg(sock, &msg, 0)); 699} 700 701/* 702 * Get the effective UID of the sending process. Used by rpcbind and keyserv 703 * (AF_LOCAL). 704 */ 705int 706__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) 707{ 708 struct cmsgcred *cmcred; 709 struct cmessage *cm; 710 struct cmsghdr *cmp; 711 712 cm = (struct cmessage *)transp->xp_verf.oa_base; 713 714 if (cm == NULL) 715 return (-1); 716 cmp = &cm->cmsg; 717 if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET || 718 cmp->cmsg_type != SCM_CREDS) 719 return (-1); 720 721 cmcred = __svc_getcallercreds(transp); 722 if (cmcred == NULL) 723 return (-1); 724 *uid = cmcred->cmcred_euid; 725 return (0); 726} 727