]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/rpc/svc_vc.c
This commit was generated by cvs2svn to compensate for changes in r105672,
[FreeBSD/FreeBSD.git] / lib / libc / rpc / svc_vc.c
1 /*      $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $  */
2
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user.
10  * 
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  * 
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  * 
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  * 
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  * 
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31
32 #if defined(LIBC_SCCS) && !defined(lint)
33 static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
34 static char *sccsid = "@(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC";
35 #endif
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
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
71 struct cmessage {
72         struct cmsghdr cmsg;
73         struct cmsgcred cmcred;
74 };
75
76 static SVCXPRT *makefd_xprt(int, u_int, u_int);
77 static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
78 static enum xprt_stat rendezvous_stat(SVCXPRT *);
79 static void svc_vc_destroy(SVCXPRT *);
80 static int read_vc(void *, void *, int);
81 static int write_vc(void *, void *, int);
82 static enum xprt_stat svc_vc_stat(SVCXPRT *);
83 static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
84 static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
85 static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
86 static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
87 static void svc_vc_rendezvous_ops(SVCXPRT *);
88 static void svc_vc_ops(SVCXPRT *);
89 static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
90 static int __msgread_withcred(int, void *, size_t, struct cmessage *);
91 static int __msgwrite(int, void *, size_t);
92
93 struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
94         u_int sendsize;
95         u_int recvsize;
96 };
97
98 struct 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  */
121 SVCXPRT *
122 svc_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 = 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);
173 cleanup_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  */
183 SVCXPRT *
184 svc_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
233 freedata:
234         if (ret->xp_ltaddr.buf != NULL)
235                 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
236
237         return NULL;
238 }
239
240 static SVCXPRT *
241 makefd_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             xprt, read_vc, write_vc);
269         xprt->xp_p1 = 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);
278 done:
279         return (xprt);
280 }
281
282 /*ARGSUSED*/
283 static bool_t
284 rendezvous_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;
298 again:
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 #ifdef PORTMAP
316         if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
317                 xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
318                 xprt->xp_addrlen = sizeof (struct sockaddr_in);
319         }
320 #endif                          /* PORTMAP */
321         if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
322                 len = 1;
323                 /* XXX fvdl - is this useful? */
324                 _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
325         }
326         return (FALSE); /* there is never an rpc msg to be processed */
327 }
328
329 /*ARGSUSED*/
330 static enum xprt_stat
331 rendezvous_stat(xprt)
332         SVCXPRT *xprt;
333 {
334
335         return (XPRT_IDLE);
336 }
337
338 static void
339 svc_vc_destroy(xprt)
340         SVCXPRT *xprt;
341 {
342         struct cf_conn *cd;
343         struct cf_rendezvous *r;
344
345         assert(xprt != NULL);
346
347         cd = (struct cf_conn *)xprt->xp_p1;
348
349         xprt_unregister(xprt);
350         if (xprt->xp_fd != RPC_ANYFD)
351                 (void)_close(xprt->xp_fd);
352         if (xprt->xp_port != 0) {
353                 /* a rendezvouser socket */
354                 r = (struct cf_rendezvous *)xprt->xp_p1;
355                 mem_free(r, sizeof (struct cf_rendezvous));
356                 xprt->xp_port = 0;
357         } else {
358                 /* an actual connection socket */
359                 XDR_DESTROY(&(cd->xdrs));
360                 mem_free(cd, sizeof(struct cf_conn));
361         }
362         if (xprt->xp_rtaddr.buf)
363                 mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
364         if (xprt->xp_ltaddr.buf)
365                 mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
366         if (xprt->xp_tp)
367                 free(xprt->xp_tp);
368         if (xprt->xp_netid)
369                 free(xprt->xp_netid);
370         mem_free(xprt, sizeof(SVCXPRT));
371 }
372
373 /*ARGSUSED*/
374 static bool_t
375 svc_vc_control(xprt, rq, in)
376         SVCXPRT *xprt;
377         const u_int rq;
378         void *in;
379 {
380         return (FALSE);
381 }
382
383 /*
384  * reads data from the tcp or uip connection.
385  * any error is fatal and the connection is closed.
386  * (And a read of zero bytes is a half closed stream => error.)
387  * All read operations timeout after 35 seconds.  A timeout is
388  * fatal for the connection.
389  */
390 static int
391 read_vc(xprtp, buf, len)
392         void *xprtp;
393         void *buf;
394         int len;
395 {
396         SVCXPRT *xprt;
397         int sock;
398         int milliseconds = 35 * 1000;
399         struct pollfd pollfd;
400         struct sockaddr *sa;
401         struct cmessage *cm;
402
403         xprt = (SVCXPRT *)xprtp;
404         assert(xprt != NULL);
405
406         sock = xprt->xp_fd;
407
408         do {
409                 pollfd.fd = sock;
410                 pollfd.events = POLLIN;
411                 pollfd.revents = 0;
412                 switch (_poll(&pollfd, 1, milliseconds)) {
413                 case -1:
414                         if (errno == EINTR)
415                                 continue;
416                         /*FALLTHROUGH*/
417                 case 0:
418                         goto fatal_err;
419
420                 default:
421                         break;
422                 }
423         } while ((pollfd.revents & POLLIN) == 0);
424
425         cm = NULL;
426         sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
427         if (sa->sa_family == AF_LOCAL) {
428                 cm = (struct cmessage *)xprt->xp_verf.oa_base;
429                 if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
430                         xprt->xp_p2 = &cm->cmcred;
431                         return (len);
432                 } else
433                         goto fatal_err;
434         } else {
435                 if ((len = _read(sock, buf, (size_t)len)) > 0)
436                         return (len);
437         }
438
439 fatal_err:
440         ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
441         return (-1);
442 }
443
444 /*
445  * writes data to the tcp connection.
446  * Any error is fatal and the connection is closed.
447  */
448 static int
449 write_vc(xprtp, buf, len)
450         void *xprtp;
451         void *buf;
452         int len;
453 {
454         SVCXPRT *xprt;
455         int i, cnt;
456         struct sockaddr *sa;
457
458         xprt = (SVCXPRT *)xprtp;
459         assert(xprt != NULL);
460         
461         sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
462         if (sa->sa_family == AF_LOCAL) {
463                 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
464                         if ((i = __msgwrite(xprt->xp_fd, buf,
465                             (size_t)cnt)) < 0) {
466                                 ((struct cf_conn *)(xprt->xp_p1))->strm_stat =
467                                     XPRT_DIED;
468                                 return (-1);
469                         }
470                 }
471         } else {
472                 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
473                         if ((i = _write(xprt->xp_fd, buf,
474                             (size_t)cnt)) < 0) {
475                                 ((struct cf_conn *)(xprt->xp_p1))->strm_stat =
476                                     XPRT_DIED;
477                                 return (-1);
478                         }
479                 }
480         }
481
482         return (len);
483 }
484
485 static enum xprt_stat
486 svc_vc_stat(xprt)
487         SVCXPRT *xprt;
488 {
489         struct cf_conn *cd;
490
491         assert(xprt != NULL);
492
493         cd = (struct cf_conn *)(xprt->xp_p1);
494
495         if (cd->strm_stat == XPRT_DIED)
496                 return (XPRT_DIED);
497         if (! xdrrec_eof(&(cd->xdrs)))
498                 return (XPRT_MOREREQS);
499         return (XPRT_IDLE);
500 }
501
502 static bool_t
503 svc_vc_recv(xprt, msg)
504         SVCXPRT *xprt;
505         struct rpc_msg *msg;
506 {
507         struct cf_conn *cd;
508         XDR *xdrs;
509
510         assert(xprt != NULL);
511         assert(msg != NULL);
512
513         cd = (struct cf_conn *)(xprt->xp_p1);
514         xdrs = &(cd->xdrs);
515
516         xdrs->x_op = XDR_DECODE;
517         (void)xdrrec_skiprecord(xdrs);
518         if (xdr_callmsg(xdrs, msg)) {
519                 cd->x_id = msg->rm_xid;
520                 return (TRUE);
521         }
522         cd->strm_stat = XPRT_DIED;
523         return (FALSE);
524 }
525
526 static bool_t
527 svc_vc_getargs(xprt, xdr_args, args_ptr)
528         SVCXPRT *xprt;
529         xdrproc_t xdr_args;
530         void *args_ptr;
531 {
532
533         assert(xprt != NULL);
534         /* args_ptr may be NULL */
535         return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
536             args_ptr));
537 }
538
539 static bool_t
540 svc_vc_freeargs(xprt, xdr_args, args_ptr)
541         SVCXPRT *xprt;
542         xdrproc_t xdr_args;
543         void *args_ptr;
544 {
545         XDR *xdrs;
546
547         assert(xprt != NULL);
548         /* args_ptr may be NULL */
549
550         xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
551
552         xdrs->x_op = XDR_FREE;
553         return ((*xdr_args)(xdrs, args_ptr));
554 }
555
556 static bool_t
557 svc_vc_reply(xprt, msg)
558         SVCXPRT *xprt;
559         struct rpc_msg *msg;
560 {
561         struct cf_conn *cd;
562         XDR *xdrs;
563         bool_t stat;
564
565         assert(xprt != NULL);
566         assert(msg != NULL);
567
568         cd = (struct cf_conn *)(xprt->xp_p1);
569         xdrs = &(cd->xdrs);
570
571         xdrs->x_op = XDR_ENCODE;
572         msg->rm_xid = cd->x_id;
573         stat = xdr_replymsg(xdrs, msg);
574         (void)xdrrec_endofrecord(xdrs, TRUE);
575         return (stat);
576 }
577
578 static void
579 svc_vc_ops(xprt)
580         SVCXPRT *xprt;
581 {
582         static struct xp_ops ops;
583         static struct xp_ops2 ops2;
584         extern mutex_t ops_lock;
585
586 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
587
588         mutex_lock(&ops_lock);
589         if (ops.xp_recv == NULL) {
590                 ops.xp_recv = svc_vc_recv;
591                 ops.xp_stat = svc_vc_stat;
592                 ops.xp_getargs = svc_vc_getargs;
593                 ops.xp_reply = svc_vc_reply;
594                 ops.xp_freeargs = svc_vc_freeargs;
595                 ops.xp_destroy = svc_vc_destroy;
596                 ops2.xp_control = svc_vc_control;
597         }
598         xprt->xp_ops = &ops;
599         xprt->xp_ops2 = &ops2;
600         mutex_unlock(&ops_lock);
601 }
602
603 static void
604 svc_vc_rendezvous_ops(xprt)
605         SVCXPRT *xprt;
606 {
607         static struct xp_ops ops;
608         static struct xp_ops2 ops2;
609         extern mutex_t ops_lock;
610
611         mutex_lock(&ops_lock);
612         if (ops.xp_recv == NULL) {
613                 ops.xp_recv = rendezvous_request;
614                 ops.xp_stat = rendezvous_stat;
615                 ops.xp_getargs =
616                     (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
617                 ops.xp_reply =
618                     (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
619                 ops.xp_freeargs =
620                     (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort,
621                 ops.xp_destroy = svc_vc_destroy;
622                 ops2.xp_control = svc_vc_control;
623         }
624         xprt->xp_ops = &ops;
625         xprt->xp_ops2 = &ops2;
626         mutex_unlock(&ops_lock);
627 }
628
629 int
630 __msgread_withcred(sock, buf, cnt, cmp)
631         int sock;
632         void *buf;
633         size_t cnt;
634         struct cmessage *cmp;
635 {
636         struct iovec iov[1];
637         struct msghdr msg;
638         union {
639                 struct cmsghdr cmsg;
640                 char control[CMSG_SPACE(sizeof(struct cmsgcred))];
641         } cm;
642         int ret;
643
644  
645         bzero(&cm, sizeof(cm));
646         iov[0].iov_base = buf;
647         iov[0].iov_len = cnt;
648  
649         msg.msg_iov = iov;
650         msg.msg_iovlen = 1;
651         msg.msg_name = NULL;
652         msg.msg_namelen = 0;
653         msg.msg_control = &cm;
654         msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
655         msg.msg_flags = 0;
656  
657         ret = _recvmsg(sock, &msg, 0);
658         bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg));
659         bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred));
660
661         if (msg.msg_controllen == 0 ||
662            (msg.msg_flags & MSG_CTRUNC) != 0)
663                 return (-1);
664
665         return (ret);
666 }
667
668 static int
669 __msgwrite(sock, buf, cnt)
670         int sock;
671         void *buf;
672         size_t cnt;
673 {
674         struct iovec iov[1];
675         struct msghdr msg;
676         struct cmessage cm;
677  
678         bzero((char *)&cm, sizeof(cm));
679         iov[0].iov_base = buf;
680         iov[0].iov_len = cnt;
681  
682         cm.cmsg.cmsg_type = SCM_CREDS;
683         cm.cmsg.cmsg_level = SOL_SOCKET;
684         cm.cmsg.cmsg_len = sizeof(struct cmessage);
685  
686         msg.msg_iov = iov;
687         msg.msg_iovlen = 1;
688         msg.msg_name = NULL;
689         msg.msg_namelen = 0;
690         msg.msg_control = &cm;
691         msg.msg_controllen = sizeof(struct cmessage);
692         msg.msg_flags = 0;
693
694         return(_sendmsg(sock, &msg, 0));
695 }
696
697 /*
698  * Get the effective UID of the sending process. Used by rpcbind and keyserv
699  * (AF_LOCAL).
700  */
701 int
702 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid)
703 {
704         struct cmsgcred *cmcred;
705         struct cmessage *cm;
706         struct cmsghdr *cmp;
707   
708         cm = (struct cmessage *)transp->xp_verf.oa_base;
709         
710         if (cm == NULL)
711                 return (-1);
712         cmp = &cm->cmsg;
713         if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET ||
714            cmp->cmsg_type != SCM_CREDS)
715                 return (-1);
716  
717         cmcred = __svc_getcallercreds(transp);
718         if (cmcred == NULL)
719                 return (-1); 
720         *uid = cmcred->cmcred_euid;
721         return (0);
722 }