8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / rpcbind / rpcb_svc_com.c
blobb7a46378ea407c2fa15e56ae1519e1836cb66558
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2017 Joyent Inc
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
42 * rpcb_svc_com.c
43 * The commom server procedure for the rpcbind.
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <rpc/rpc.h>
54 #include <rpc/rpcb_prot.h>
55 #include <rpcsvc/svc_dg_priv.h>
56 #include <netconfig.h>
57 #include <sys/param.h>
58 #include <errno.h>
59 #include <zone.h>
60 #include <sys/poll.h>
61 #include <sys/stropts.h>
62 #ifdef PORTMAP
63 #include <netinet/in.h>
64 #include <rpc/pmap_prot.h>
65 #else
66 #define PMAPVERS 2
67 #endif /* PORTMAP */
68 #include <syslog.h>
69 #include <netdir.h>
70 #include <ucred.h>
71 #include <alloca.h>
72 #include <rpcsvc/yp_prot.h>
73 #include <nfs/nfs.h>
74 #include <nfs/nfs_acl.h>
75 #include <rpcsvc/mount.h>
76 #include <nfs/nfs_acl.h>
77 #include <rpc/key_prot.h>
78 #include <rpcsvc/yp_prot.h>
79 #include <rpcsvc/rquota.h>
80 #include <rpcsvc/yppasswd.h>
81 #include <rpcsvc/ypupd.h>
82 #include <assert.h>
83 #include <synch.h>
84 #include "rpcbind.h"
85 #include <sys/debug.h>
87 static struct finfo *forward_register(ulong_t, struct netbuf *, int, char *);
88 static void forward_destroy(struct finfo *);
89 static void handle_reply(svc_input_id_t, int, unsigned int, void *);
90 static int netbufcmp(struct netbuf *, struct netbuf *);
91 static void netbuffree(struct netbuf *);
92 static struct netbuf *netbufdup(struct netbuf *);
93 static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
94 static rpcblist_ptr find_service(ulong_t, ulong_t, char *);
95 #ifdef PORTMAP
96 static int add_pmaplist(RPCB *);
97 #endif
99 zoneid_t myzone;
102 * Set a mapping of program, version, netid
104 bool_t
105 rpcbproc_set_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
106 int rpcbversnum)
108 char owner[64];
110 *result = map_set(regp, getowner(rqstp->rq_xprt, owner));
112 rpcbs_set(rpcbversnum - PMAPVERS, *result);
114 return (TRUE);
117 bool_t
118 map_set(RPCB *regp, char *owner)
120 RPCB *a;
121 rpcblist_ptr rbl, fnd;
124 * check to see if already used
125 * find_service returns a hit even if
126 * the versions don't match, so check for it
128 (void) rw_wrlock(&list_rbl_lock);
129 #ifdef PORTMAP
130 (void) rw_wrlock(&list_pml_lock);
131 #endif /* PORTMAP */
132 fnd = find_service(regp->r_prog, regp->r_vers, regp->r_netid);
133 if (fnd && (fnd->rpcb_map.r_vers == regp->r_vers)) {
134 if (strcmp(fnd->rpcb_map.r_addr, regp->r_addr) == 0) {
136 * if these match then it is already
137 * registered so just say "OK".
139 #ifdef PORTMAP
140 (void) rw_unlock(&list_pml_lock);
141 #endif /* PORTMAP */
142 (void) rw_unlock(&list_rbl_lock);
143 return (TRUE);
144 } else {
146 * Check if server is up. If so, return FALSE.
147 * If not, cleanup old registrations for the
148 * program and register the new server.
150 if (is_bound(fnd->rpcb_map.r_netid,
151 fnd->rpcb_map.r_addr)) {
152 #ifdef PORTMAP
153 (void) rw_unlock(&list_pml_lock);
154 #endif /* PORTMAP */
155 (void) rw_unlock(&list_rbl_lock);
156 return (FALSE);
159 delete_prog(regp->r_prog);
160 fnd = NULL;
163 #ifdef PORTMAP
164 (void) rw_unlock(&list_pml_lock);
165 #endif /* PORTMAP */
168 * add to the end of the list
170 rbl = malloc(sizeof (RPCBLIST));
171 if (rbl == NULL) {
172 (void) rw_unlock(&list_rbl_lock);
173 return (FALSE);
175 a = &rbl->rpcb_map;
176 a->r_prog = regp->r_prog;
177 a->r_vers = regp->r_vers;
178 a->r_netid = strdup(regp->r_netid);
179 a->r_addr = strdup(regp->r_addr);
180 a->r_owner = strdup(owner);
181 if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
182 (void) rw_unlock(&list_rbl_lock);
183 delete_rbl(rbl);
184 return (FALSE);
186 rbl->rpcb_next = NULL;
187 if (list_rbl == NULL) {
188 list_rbl = rbl;
189 } else {
190 for (fnd = list_rbl; fnd->rpcb_next; fnd = fnd->rpcb_next)
192 fnd->rpcb_next = rbl;
195 #ifdef PORTMAP
196 (void) add_pmaplist(regp);
197 #endif
198 (void) rw_unlock(&list_rbl_lock);
199 return (TRUE);
203 * Unset a mapping of program, version, netid
205 bool_t
206 rpcbproc_unset_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
207 int rpcbversnum)
209 char owner[64];
211 *result = map_unset(regp, getowner(rqstp->rq_xprt, owner));
213 rpcbs_unset(rpcbversnum - PMAPVERS, *result);
215 return (TRUE);
218 bool_t
219 map_unset(RPCB *regp, char *owner)
221 #ifdef PORTMAP
222 int ans = 0;
223 #endif
224 rpcblist_ptr rbl, next, prev = NULL;
226 if (owner == NULL)
227 return (0);
229 (void) rw_wrlock(&list_rbl_lock);
230 for (rbl = list_rbl; rbl != NULL; rbl = next) {
231 next = rbl->rpcb_next;
233 if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
234 (rbl->rpcb_map.r_vers != regp->r_vers) ||
235 (regp->r_netid[0] && strcasecmp(regp->r_netid,
236 rbl->rpcb_map.r_netid))) {
237 /* prev moves forwards */
238 prev = rbl;
239 continue;
243 * Check whether appropriate uid. Unset only
244 * if superuser or the owner itself.
246 if (strcmp(owner, "superuser") &&
247 strcmp(rbl->rpcb_map.r_owner, owner)) {
248 (void) rw_unlock(&list_rbl_lock);
249 return (0);
252 /* prev stays */
253 #ifdef PORTMAP
254 ans = 1;
255 #endif
256 delete_rbl(rbl);
258 if (prev == NULL)
259 list_rbl = next;
260 else
261 prev->rpcb_next = next;
263 #ifdef PORTMAP
264 if (ans != 0) {
265 (void) rw_wrlock(&list_pml_lock);
266 (void) del_pmaplist(regp);
267 (void) rw_unlock(&list_pml_lock);
269 #endif
270 (void) rw_unlock(&list_rbl_lock);
273 * We return 1 either when the entry was not there or it
274 * was able to unset it. It can come to this point only if
275 * at least one of the conditions is true.
277 return (1);
280 void
281 delete_rbl(rpcblist_ptr rbl)
283 free(rbl->rpcb_map.r_addr);
284 free(rbl->rpcb_map.r_netid);
285 free(rbl->rpcb_map.r_owner);
286 free(rbl);
289 void
290 delete_prog(rpcprog_t prog)
292 rpcblist_ptr rbl, next, prev = NULL;
294 assert(RW_WRITE_HELD(&list_rbl_lock));
296 for (rbl = list_rbl; rbl != NULL; rbl = next) {
297 next = rbl->rpcb_next;
299 if (rbl->rpcb_map.r_prog != prog ||
300 is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) {
301 prev = rbl;
302 continue;
305 #ifdef PORTMAP
306 (void) del_pmaplist(&rbl->rpcb_map);
307 #endif
308 delete_rbl(rbl);
310 if (prev == NULL)
311 list_rbl = next;
312 else
313 prev->rpcb_next = next;
318 * Lookup the mapping for a program, version and return its
319 * address. Assuming that the caller wants the address of the
320 * server running on the transport on which the request came.
322 * For RPCBPROC_GETVERSADDR it will return a service with the exact version
323 * number only.
325 * Otherwise, even if a service with a different version number is available,
326 * it will return that address. The client should check with an
327 * clnt_call to verify whether the service is the one that is desired.
329 * We also try to resolve the universal address in terms of
330 * address of the caller.
332 bool_t
333 rpcbproc_getaddr_com(RPCB *regp, char **result, struct svc_req *rqstp,
334 ulong_t rpcbversnum)
336 char *saddr = NULL;
337 rpcblist_ptr fnd;
338 struct netconfig *trans_conf; /* transport netconfig */
339 SVCXPRT *transp = rqstp->rq_xprt;
340 int verstype = rqstp->rq_proc == RPCBPROC_GETVERSADDR ? RPCB_ONEVERS :
341 RPCB_ALLVERS;
342 bool_t pml_locked = FALSE;
345 * There is a potential window at startup during which rpcbind
346 * service has been established over IPv6 but not over IPv4. If an
347 * IPv4 request comes in during that window, the IP code will map
348 * it into IPv6. We could patch up the request so that it looks
349 * like IPv4 (so that rpcbind returns an IPv4 uaddr to the caller),
350 * but that requires some non-trivial code and it's hard to test.
351 * Instead, drop the request on the floor and force the caller to
352 * retransmit. By the time rpcbind sees the retransmission, IPv4
353 * service should be in place and it should see the request as
354 * IPv4, as desired.
356 trans_conf = rpcbind_get_conf(transp->xp_netid);
357 if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) {
358 struct sockaddr_in6 *rmtaddr;
360 rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
361 if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
362 syslog(LOG_DEBUG,
363 "IPv4 GETADDR request mapped to IPv6: ignoring");
364 *result = NULL;
365 return (FALSE);
369 (void) rw_rdlock(&list_rbl_lock);
370 retry:
371 fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
372 if (fnd && ((verstype == RPCB_ALLVERS) ||
373 (regp->r_vers == fnd->rpcb_map.r_vers))) {
374 if (*(regp->r_addr) != '\0') { /* may contain a hint about */
375 saddr = regp->r_addr; /* the interface that we */
376 } /* should use */
377 if (!(*result = mergeaddr(transp, transp->xp_netid,
378 fnd->rpcb_map.r_addr, saddr))) {
379 /* Try whatever we have */
380 *result = strdup(fnd->rpcb_map.r_addr);
381 } else if (!(*result)[0]) {
382 if (!pml_locked) {
383 (void) rw_unlock(&list_rbl_lock);
384 (void) rw_wrlock(&list_rbl_lock);
385 #ifdef PORTMAP
386 (void) rw_wrlock(&list_pml_lock);
387 #endif /* PORTMAP */
388 pml_locked = TRUE;
389 goto retry;
392 * The server died. Unset all versions of this prog.
394 delete_prog(regp->r_prog);
395 *result = NULL;
397 } else {
398 *result = NULL;
400 #ifdef PORTMAP
401 if (pml_locked)
402 (void) rw_unlock(&list_pml_lock);
403 #endif /* PORTMAP */
404 (void) rw_unlock(&list_rbl_lock);
406 rpcbs_getaddr(rpcbversnum - PMAPVERS, regp->r_prog, regp->r_vers,
407 transp->xp_netid, *result);
408 return (TRUE);
411 /* ARGSUSED */
412 bool_t
413 rpcbproc_dump_com(void *argp, rpcblist_ptr **result)
416 * list_rbl_lock is unlocked in xdr_rpcblist_ptr_ptr()
418 (void) rw_rdlock(&list_rbl_lock);
419 *result = &list_rbl;
420 return (TRUE);
423 bool_t
424 xdr_rpcblist_ptr_ptr(XDR *xdrs, rpcblist_ptr **objp)
426 if (xdrs->x_op == XDR_FREE) {
428 * list_rbl_lock is locked in rpcbproc_dump_com()
430 rw_unlock(&list_rbl_lock);
431 return (TRUE);
434 return (xdr_rpcblist_ptr(xdrs, *objp));
437 /* ARGSUSED */
438 bool_t
439 rpcbproc_gettime_com(void *argp, ulong_t *result)
441 (void) time((time_t *)result);
443 return (TRUE);
447 * Convert uaddr to taddr. Should be used only by
448 * local servers/clients. (kernel level stuff only)
450 bool_t
451 rpcbproc_uaddr2taddr_com(char **uaddrp, struct netbuf *result,
452 struct svc_req *rqstp)
454 struct netconfig *nconf;
455 struct netbuf *taddr;
457 if (((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL) ||
458 ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
459 (void) memset(result, 0, sizeof (*result));
460 return (TRUE);
463 memcpy(result, taddr, sizeof (*result));
464 free(taddr);
466 return (TRUE);
470 * Convert taddr to uaddr. Should be used only by
471 * local servers/clients. (kernel level stuff only)
473 bool_t
474 rpcbproc_taddr2uaddr_com(struct netbuf *taddr, char **result,
475 struct svc_req *rqstp)
477 struct netconfig *nconf;
479 if ((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL)
480 *result = NULL;
481 else
482 *result = taddr2uaddr(nconf, taddr);
484 return (TRUE);
488 * Stuff for the rmtcall service
490 bool_t
491 xdr_rpcb_rmtcallargs(XDR *xdrs, rpcb_rmtcallargs *objp)
493 if (!xdr_u_long(xdrs, &objp->prog))
494 return (FALSE);
495 if (!xdr_u_long(xdrs, &objp->vers))
496 return (FALSE);
497 if (!xdr_u_long(xdrs, &objp->proc))
498 return (FALSE);
499 if (!xdr_bytes(xdrs, (char **)&objp->args.args_val,
500 (uint_t *)&objp->args.args_len, ~0))
501 return (FALSE);
502 return (TRUE);
505 #ifdef PORTMAP
506 bool_t
507 xdr_rmtcallres(XDR *xdrs, rmtcallres *objp)
509 if (!xdr_u_long(xdrs, &objp->port))
510 return (FALSE);
511 if (!xdr_bytes(xdrs, (char **)&objp->res.res_val,
512 (uint_t *)&objp->res.res_len, ~0))
513 return (FALSE);
514 return (TRUE);
516 #endif
518 bool_t
519 xdr_rpcb_rmtcallres(XDR *xdrs, rpcb_rmtcallres *objp)
521 if (!xdr_string(xdrs, &objp->addr, ~0))
522 return (FALSE);
523 if (!xdr_bytes(xdrs, (char **)&objp->results.results_val,
524 (uint_t *)&objp->results.results_len, ~0))
525 return (FALSE);
526 return (TRUE);
529 struct rmtcallfd_list {
530 int fd;
531 char *netid;
532 struct rmtcallfd_list *next;
535 static struct rmtcallfd_list *rmthead;
536 static struct rmtcallfd_list *rmttail;
538 #define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
541 create_rmtcall_fd(struct netconfig *nconf)
543 int fd;
544 struct rmtcallfd_list *rmt;
546 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
547 if (debugging)
548 fprintf(stderr, "create_rmtcall_fd: couldn't open "
549 "\"%s\" (errno %d, t_errno %d)\n",
550 nconf->nc_device, errno, t_errno);
551 return (-1);
554 if (t_bind(fd, NULL, NULL) == -1) {
555 if (debugging)
556 fprintf(stderr, "create_rmtcall_fd: couldn't bind to "
557 "fd for \"%s\" (errno %d, t_errno %d)\n",
558 nconf->nc_device, errno, t_errno);
559 return (-1);
562 rmt = malloc(sizeof (struct rmtcallfd_list));
563 if (rmt == NULL) {
564 syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
565 return (-1);
568 rmt->netid = strdup(nconf->nc_netid);
569 if (rmt->netid == NULL) {
570 free(rmt);
571 syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
572 return (-1);
575 if (svc_add_input(fd, MASKVAL, handle_reply, rmt->netid) == -1) {
576 free(rmt->netid);
577 free(rmt);
578 syslog(LOG_ERR, "create_rmtcall_fd: svc_add_input() failed!");
579 return (-1);
582 rmt->fd = fd;
583 rmt->next = NULL;
584 if (rmthead == NULL) {
585 rmthead = rmt;
586 rmttail = rmt;
587 } else {
588 rmttail->next = rmt;
589 rmttail = rmt;
592 return (fd);
595 static int
596 find_rmtcallfd_by_netid(char *netid)
598 struct rmtcallfd_list *rmt;
600 for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
601 if (strcmp(netid, rmt->netid) == 0) {
602 return (rmt->fd);
605 return (-1);
608 #define MAXTIME_OFF 300 /* 5 minutes timeout for rmtcalls */
610 struct finfo {
611 struct finfo *prev;
612 struct finfo *next;
613 int flag;
614 #define FINFO_ACTIVE 0x1
615 ulong_t caller_xid;
616 struct netbuf *caller_addr;
617 ulong_t forward_xid;
618 int forward_fd;
619 char *uaddr;
620 struct t_unitdata *reply_data;
621 struct rpc_err reply_error;
622 uint_t res_len;
623 void *res_val;
624 cond_t cv;
628 * finfo_lock protects rpcb_rmtcalls, rpcb_rmtcalls_max, lastxid,
629 * fihead, and fitail.
631 static mutex_t finfo_lock = DEFAULTMUTEX;
633 static int rpcb_rmtcalls;
634 static int rpcb_rmtcalls_max;
635 static ulong_t lastxid;
636 static struct finfo *fihead;
637 static struct finfo *fitail;
639 void
640 set_rpcb_rmtcalls_max(int max)
642 (void) mutex_lock(&finfo_lock);
643 rpcb_rmtcalls_max = max;
644 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
645 assert(fitail != NULL);
646 (void) cond_signal(&fitail->cv);
648 (void) mutex_unlock(&finfo_lock);
652 * Call a remote procedure service. This procedure is very quiet when things
653 * go wrong. The proc is written to support broadcast rpc. In the broadcast
654 * case, a machine should shut-up instead of complain, lest the requestor be
655 * overrun with complaints at the expense of not hearing a valid reply.
656 * When receiving a request and verifying that the service exists, we
658 * receive the request
660 * open a new TLI endpoint on the same transport on which we received
661 * the original request
663 * remember the original request's XID (which requires knowing the format
664 * of the svc_dg_data structure)
666 * forward the request, with a new XID, to the requested service,
667 * remembering the XID used to send this request (for later use in
668 * reassociating the answer with the original request), the requestor's
669 * address, the file descriptor on which the forwarded request is
670 * made and the service's address
672 * wait for either the timeout or the condition variable is signalled from
673 * handle_reply().
675 * At some time in the future, a reply will be received from the service to
676 * which we forwarded the request. At that time, svc_run() detect that the
677 * socket used was for forwarding and call handle_reply() to
679 * receive the reply
681 * bundle the reply, along with the service's universal address
683 * put the reply into the particular finfo
685 * signal the condition variable.
688 #define RPC_BUF_MAX 65536 /* can be raised if required */
691 * This is from ../ypcmd/yp_b.h
692 * It does not appear in <rpcsvc/yp_prot.h>
694 #define YPBINDPROG ((ulong_t)100007)
695 #define YPBINDPROC_SETDOM ((ulong_t)2)
698 * reply_type - which proc number
699 * versnum - which vers was called
701 void
702 rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp, ulong_t reply_type,
703 int versnum)
705 struct t_info tinfo;
706 uint_t sendsz;
708 rpcb_rmtcallargs arg;
709 rpcblist_ptr rbl;
711 struct netconfig *nconf;
712 struct netbuf *caller;
713 struct nd_mergearg ma;
714 int stat;
716 int fd;
717 struct svc_dg_data *bd;
718 struct finfo *fi;
720 struct rpc_msg call_msg;
721 char outbuf[RPC_BUF_MAX];
722 char *outbuf_alloc = NULL;
723 XDR outxdr;
724 bool_t outxdr_created = FALSE;
726 AUTH *auth;
728 struct t_unitdata tu_data;
729 struct netbuf *na;
731 timestruc_t to;
733 (void) mutex_lock(&finfo_lock);
734 if (!allow_indirect || rpcb_rmtcalls_max == 0) {
735 (void) mutex_unlock(&finfo_lock);
736 return;
738 (void) mutex_unlock(&finfo_lock);
740 if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
741 if (reply_type == RPCBPROC_INDIRECT)
742 svcerr_systemerr(transp);
743 return;
745 if (tinfo.servtype != T_CLTS)
746 return; /* Only datagram type accepted */
748 sendsz = __rpc_get_t_size(0, tinfo.tsdu);
749 if (sendsz == 0) { /* data transfer not supported */
750 if (reply_type == RPCBPROC_INDIRECT)
751 svcerr_systemerr(transp);
752 return;
755 * Should be multiple of 4 for XDR.
757 sendsz = ((sendsz + 3) / 4) * 4;
759 (void) memset((char *)&arg, 0, sizeof (arg));
760 if (!svc_getargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg)) {
761 if (reply_type == RPCBPROC_INDIRECT)
762 svcerr_decode(transp);
763 if (debugging)
764 fprintf(stderr,
765 "rpcbproc_callit_com: svc_getargs failed\n");
766 goto error;
770 * Disallow calling rpcbind for certain procedures.
771 * Allow calling NULLPROC - per man page on rpcb_rmtcall().
772 * switch is in alphabetical order.
774 if (arg.proc != NULLPROC) {
775 switch (arg.prog) {
776 case KEY_PROG:
777 if (debugging)
778 fprintf(stderr,
779 "rpcbind: rejecting KEY_PROG(%d)\n",
780 arg.proc);
781 goto error;
782 case MOUNTPROG:
783 if (arg.proc != MOUNTPROC_MNT)
784 break;
786 * In Solaris 2.6, the host-based accesss control
787 * is done by the NFS server on each request.
788 * Prior to 2.6 we rely on mountd.
790 if (debugging)
791 fprintf(stderr,
792 "rpcbind: rejecting MOUNTPROG(%d)\n",
793 arg.proc);
794 goto error;
795 case NFS_ACL_PROGRAM:
796 if (debugging)
797 fprintf(stderr,
798 "rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
799 arg.proc);
800 goto error;
801 case NFS_PROGRAM:
802 /* also NFS3_PROGRAM */
803 if (debugging)
804 fprintf(stderr,
805 "rpcbind: rejecting NFS_PROGRAM(%d)\n",
806 arg.proc);
807 goto error;
808 case RPCBPROG:
810 * Disallow calling rpcbind for certain procedures.
811 * Luckily Portmap set/unset/callit also have same
812 * procedure numbers. So, will not check for those.
814 switch (arg.proc) {
815 case RPCBPROC_SET:
816 case RPCBPROC_UNSET:
817 case RPCBPROC_CALLIT:
818 case RPCBPROC_INDIRECT:
819 if (reply_type == RPCBPROC_INDIRECT)
820 svcerr_weakauth(transp); /* XXX */
821 if (debugging)
822 fprintf(stderr, "rpcbproc_callit_com: "
823 "calling RPCBPROG procs SET, "
824 "UNSET, CALLIT, or INDIRECT not "
825 "allowed\n");
826 goto error;
827 default:
829 * Ideally, we should have called rpcb_service()
830 * or pmap_service() with appropriate parameters
831 * instead of going about in a roundabout
832 * manner. Hopefully, this case should happen
833 * rarely.
835 break;
837 break;
838 case RQUOTAPROG:
839 if (debugging)
840 fprintf(stderr,
841 "rpcbind: rejecting RQUOTAPROG(%d)\n",
842 arg.proc);
843 goto error;
844 case YPPASSWDPROG:
845 if (debugging)
846 fprintf(stderr,
847 "rpcbind: rejecting YPPASSWDPROG(%d)\n",
848 arg.proc);
849 goto error;
850 case YPU_PROG:
851 if (debugging)
852 fprintf(stderr,
853 "rpcbind: rejecting YPU_PROG(%d)\n",
854 arg.proc);
855 goto error;
856 case YPBINDPROG:
857 if (arg.proc != YPBINDPROC_SETDOM)
858 break;
859 if (debugging)
860 fprintf(stderr,
861 "rpcbind: rejecting YPBINDPROG(%d)\n",
862 arg.proc);
863 goto error;
864 case YPPROG:
865 switch (arg.proc) {
866 case YPPROC_FIRST:
867 case YPPROC_NEXT:
868 case YPPROC_MATCH:
869 case YPPROC_ALL:
870 if (debugging)
871 fprintf(stderr,
872 "rpcbind: rejecting YPPROG(%d)\n",
873 arg.proc);
874 goto error;
875 default:
876 break;
878 break;
879 default:
880 break;
884 (void) rw_rdlock(&list_rbl_lock);
885 rbl = find_service(arg.prog, arg.vers, transp->xp_netid);
887 rpcbs_rmtcall(versnum - PMAPVERS, reply_type, arg.prog, arg.vers,
888 arg.proc, transp->xp_netid, rbl);
890 if (rbl == NULL) {
891 (void) rw_unlock(&list_rbl_lock);
892 if (reply_type == RPCBPROC_INDIRECT)
893 svcerr_noprog(transp);
894 goto error;
896 if (rbl->rpcb_map.r_vers != arg.vers) {
897 if (reply_type == RPCBPROC_INDIRECT) {
898 ulong_t vers_low, vers_high;
900 find_versions(arg.prog, transp->xp_netid,
901 &vers_low, &vers_high);
902 (void) rw_unlock(&list_rbl_lock);
903 svcerr_progvers(transp, vers_low, vers_high);
904 } else {
905 (void) rw_unlock(&list_rbl_lock);
907 goto error;
911 * Check whether this entry is valid and a server is present
912 * Mergeaddr() returns NULL if no such entry is present, and
913 * returns "" if the entry was present but the server is not
914 * present (i.e., it crashed).
916 if (reply_type == RPCBPROC_INDIRECT) {
917 char *uaddr = mergeaddr(transp, transp->xp_netid,
918 rbl->rpcb_map.r_addr, NULL);
919 if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
920 (void) rw_unlock(&list_rbl_lock);
921 svcerr_noprog(transp);
922 goto error;
923 } else {
924 free(uaddr);
928 nconf = rpcbind_get_conf(transp->xp_netid);
929 if (nconf == NULL) {
930 (void) rw_unlock(&list_rbl_lock);
931 if (reply_type == RPCBPROC_INDIRECT)
932 svcerr_systemerr(transp);
933 if (debugging)
934 fprintf(stderr,
935 "rpcbproc_callit_com: rpcbind_get_conf failed\n");
936 goto error;
939 caller = svc_getrpccaller(transp);
940 ma.c_uaddr = taddr2uaddr(nconf, caller);
941 ma.s_uaddr = rbl->rpcb_map.r_addr;
944 * A mergeaddr operation allocates a string, which it stores in
945 * ma.m_uaddr. It's passed to forward_register() and is
946 * eventually freed by forward_destroy().
948 stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
949 (void) rw_unlock(&list_rbl_lock);
950 free(ma.c_uaddr);
951 if (stat)
952 (void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
953 nconf->nc_netid, netdir_sperror());
955 if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
956 if (reply_type == RPCBPROC_INDIRECT)
957 svcerr_systemerr(transp);
958 free(ma.m_uaddr);
959 goto error;
962 bd = get_svc_dg_data(transp);
964 assert(!MUTEX_HELD(&finfo_lock));
965 fi = forward_register(bd->su_xid, caller, fd, ma.m_uaddr);
966 if (fi == NULL) {
967 /* forward_register failed. Perhaps no memory. */
968 free(ma.m_uaddr);
969 if (debugging)
970 fprintf(stderr,
971 "rpcbproc_callit_com: forward_register failed\n");
972 assert(!MUTEX_HELD(&finfo_lock));
973 goto error;
975 /* forward_register() returns with finfo_lock held when successful */
976 assert(MUTEX_HELD(&finfo_lock));
978 if (fi->flag & FINFO_ACTIVE) {
980 * A duplicate request for the slow server. Let's not
981 * beat on it any more.
983 (void) mutex_unlock(&finfo_lock);
984 free(ma.m_uaddr);
985 if (debugging)
986 fprintf(stderr,
987 "rpcbproc_callit_com: duplicate request\n");
988 goto error;
990 fi->flag |= FINFO_ACTIVE;
992 call_msg.rm_xid = fi->forward_xid;
993 call_msg.rm_direction = CALL;
994 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
995 call_msg.rm_call.cb_prog = arg.prog;
996 call_msg.rm_call.cb_vers = arg.vers;
998 if (sendsz > RPC_BUF_MAX) {
999 outbuf_alloc = malloc(sendsz);
1000 if (outbuf_alloc == NULL) {
1001 forward_destroy(fi);
1002 (void) mutex_unlock(&finfo_lock);
1003 if (reply_type == RPCBPROC_INDIRECT)
1004 svcerr_systemerr(transp);
1005 if (debugging)
1006 fprintf(stderr,
1007 "rpcbproc_callit_com: No memory!\n");
1008 goto error;
1010 xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
1011 } else {
1012 xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
1014 outxdr_created = TRUE;
1016 if (!xdr_callhdr(&outxdr, &call_msg)) {
1017 forward_destroy(fi);
1018 (void) mutex_unlock(&finfo_lock);
1019 if (reply_type == RPCBPROC_INDIRECT)
1020 svcerr_systemerr(transp);
1021 if (debugging)
1022 fprintf(stderr,
1023 "rpcbproc_callit_com: xdr_callhdr failed\n");
1024 goto error;
1027 if (!xdr_u_long(&outxdr, &arg.proc)) {
1028 forward_destroy(fi);
1029 (void) mutex_unlock(&finfo_lock);
1030 if (reply_type == RPCBPROC_INDIRECT)
1031 svcerr_systemerr(transp);
1032 if (debugging)
1033 fprintf(stderr,
1034 "rpcbproc_callit_com: xdr_u_long failed\n");
1035 goto error;
1038 if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
1039 auth = authnone_create();
1040 } else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
1041 struct authsys_parms *au;
1043 CTASSERT(sizeof (struct authsys_parms) <= RQCRED_SIZE);
1044 au = (struct authsys_parms *)rqstp->rq_clntcred;
1045 auth = authsys_create(au->aup_machname, au->aup_uid,
1046 au->aup_gid, au->aup_len, au->aup_gids);
1047 if (auth == NULL) /* fall back */
1048 auth = authnone_create();
1049 } else {
1050 /* we do not support any other authentication scheme */
1051 forward_destroy(fi);
1052 (void) mutex_unlock(&finfo_lock);
1053 if (reply_type == RPCBPROC_INDIRECT)
1054 svcerr_weakauth(transp); /* XXX too strong.. */
1055 if (debugging)
1056 fprintf(stderr, "rpcbproc_callit_com: oa_flavor != "
1057 "AUTH_NONE and oa_flavor != AUTH_SYS\n");
1058 goto error;
1060 if (auth == NULL) {
1061 forward_destroy(fi);
1062 (void) mutex_unlock(&finfo_lock);
1063 if (reply_type == RPCBPROC_INDIRECT)
1064 svcerr_systemerr(transp);
1065 if (debugging)
1066 fprintf(stderr, "rpcbproc_callit_com: "
1067 "authwhatever_create returned NULL\n");
1068 goto error;
1070 if (!AUTH_MARSHALL(auth, &outxdr)) {
1071 forward_destroy(fi);
1072 (void) mutex_unlock(&finfo_lock);
1073 if (reply_type == RPCBPROC_INDIRECT)
1074 svcerr_systemerr(transp);
1075 AUTH_DESTROY(auth);
1076 if (debugging)
1077 fprintf(stderr,
1078 "rpcbproc_callit_com: AUTH_MARSHALL failed\n");
1079 goto error;
1081 AUTH_DESTROY(auth);
1083 if (!xdr_opaque(&outxdr, arg.args.args_val, arg.args.args_len)) {
1084 forward_destroy(fi);
1085 (void) mutex_unlock(&finfo_lock);
1086 if (reply_type == RPCBPROC_INDIRECT)
1087 svcerr_systemerr(transp);
1088 if (debugging)
1089 fprintf(stderr,
1090 "rpcbproc_callit_com: xdr_opaque failed\n");
1091 goto error;
1094 tu_data.udata.len = XDR_GETPOS(&outxdr);
1095 if (outbuf_alloc)
1096 tu_data.udata.buf = outbuf_alloc;
1097 else
1098 tu_data.udata.buf = outbuf;
1099 tu_data.opt.len = 0;
1101 na = uaddr2taddr(nconf, ma.m_uaddr);
1102 if (!na) {
1103 forward_destroy(fi);
1104 (void) mutex_unlock(&finfo_lock);
1105 if (reply_type == RPCBPROC_INDIRECT)
1106 svcerr_systemerr(transp);
1107 goto error;
1109 tu_data.addr = *na;
1111 if (t_sndudata(fd, &tu_data) == -1) {
1112 int err = errno;
1113 forward_destroy(fi);
1114 (void) mutex_unlock(&finfo_lock);
1116 netdir_free((char *)na, ND_ADDR);
1118 if (reply_type == RPCBPROC_INDIRECT)
1119 svcerr_systemerr(transp);
1120 if (debugging)
1121 fprintf(stderr,
1122 "rpcbproc_callit_com: t_sndudata failed: "
1123 "t_errno %d, errno %d\n", t_errno, err);
1124 goto error;
1127 netdir_free((char *)na, ND_ADDR);
1128 xdr_destroy(&outxdr);
1129 outxdr_created = FALSE;
1130 if (outbuf_alloc != NULL) {
1131 free(outbuf_alloc);
1132 outbuf_alloc = NULL;
1134 svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
1136 to.tv_sec = time(NULL) + MAXTIME_OFF;
1137 to.tv_nsec = 0;
1139 while (fi->reply_data == NULL &&
1140 cond_timedwait(&fi->cv, &finfo_lock, &to) != ETIME)
1143 if (fi->reply_data == NULL) {
1144 forward_destroy(fi);
1145 (void) mutex_unlock(&finfo_lock);
1147 if (reply_type == RPCBPROC_INDIRECT)
1148 svcerr_systemerr(transp);
1149 if (debugging)
1150 (void) fprintf(stderr,
1151 "rpcbproc_callit_com: timeout\n");
1152 return;
1155 if (fi->reply_error.re_status != RPC_SUCCESS) {
1156 forward_destroy(fi);
1157 (void) mutex_unlock(&finfo_lock);
1159 if (reply_type == RPCBPROC_INDIRECT)
1160 svcerr_systemerr(transp);
1161 if (debugging)
1162 (void) fprintf(stderr,
1163 "rpcbproc_callit_com: error in reply: %s\n",
1164 clnt_sperrno(fi->reply_error.re_status));
1165 return;
1168 switch (versnum) {
1169 #ifdef PORTMAP
1170 case PMAPVERS:
1172 rmtcallres result;
1173 int h1, h2, h3, h4, p1, p2;
1175 /* interpret the universal address for TCP/IP */
1176 if (sscanf(fi->uaddr, "%d.%d.%d.%d.%d.%d",
1177 &h1, &h2, &h3, &h4, &p1, &p2) != 6)
1178 break;
1180 result.port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1181 result.res.res_len = fi->res_len;
1182 result.res.res_val = fi->res_val;
1184 svc_sendreply(transp, xdr_rmtcallres, (char *)&result);
1186 break;
1187 #endif
1188 case RPCBVERS:
1189 case RPCBVERS4:
1191 rpcb_rmtcallres result;
1193 result.addr = fi->uaddr;
1194 result.results.results_len = fi->res_len;
1195 result.results.results_val = fi->res_val;
1197 svc_sendreply(transp, xdr_rpcb_rmtcallres,
1198 (char *)&result);
1200 break;
1203 forward_destroy(fi);
1204 (void) mutex_unlock(&finfo_lock);
1206 return;
1208 error:
1209 if (outxdr_created)
1210 xdr_destroy(&outxdr);
1211 free(outbuf_alloc);
1212 svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
1215 static struct finfo *forward_find(ulong_t, char *);
1218 * Adds an entry into the finfo list for the given request. Returns the finfo
1219 * and finfo_lock is left held. If duplicate request, returns finfo with
1220 * FINFO_ACTIVE, else returns finfo without FINFO_ACTIVE.
1221 * If failed, returns NULL and finfo_lock is left unheld.
1223 static struct finfo *
1224 forward_register(ulong_t caller_xid, struct netbuf *caller_addr, int forward_fd,
1225 char *uaddr)
1227 struct finfo *fi;
1229 (void) mutex_lock(&finfo_lock);
1230 if (rpcb_rmtcalls_max == 0) {
1231 (void) mutex_unlock(&finfo_lock);
1232 return (NULL);
1236 * initialization: once this has happened, lastxid will
1237 * never be 0 again, when entering or returning from this function.
1239 if (lastxid == 0)
1240 lastxid = time(NULL);
1243 * Check if it is an duplicate entry
1245 for (fi = fihead; fi != NULL; fi = fi->next) {
1246 if (fi->caller_xid == caller_xid &&
1247 netbufcmp(fi->caller_addr, caller_addr)) {
1248 assert(fi->flag & FINFO_ACTIVE);
1249 return (fi);
1253 fi = malloc(sizeof (*fi));
1254 if (fi == NULL) {
1255 (void) mutex_unlock(&finfo_lock);
1256 return (NULL);
1259 if ((fi->caller_addr = netbufdup(caller_addr)) == NULL) {
1260 (void) mutex_unlock(&finfo_lock);
1261 free(fi);
1262 return (NULL);
1266 * Generate new xid and make sure it is unique.
1268 do {
1269 lastxid++;
1270 /* avoid lastxid wraparound to 0 */
1271 if (lastxid == 0)
1272 lastxid = 1;
1273 } while (forward_find(lastxid, uaddr) != NULL);
1275 fi->prev = NULL;
1276 fi->next = fihead;
1277 if (fihead != NULL)
1278 fihead->prev = fi;
1279 fihead = fi;
1280 if (fitail == NULL)
1281 fitail = fi;
1283 fi->flag = 0;
1284 fi->caller_xid = caller_xid;
1286 fi->forward_xid = lastxid;
1287 fi->forward_fd = forward_fd;
1290 * Though uaddr is not allocated here, it will still be freed
1291 * from forward_destroy().
1293 fi->uaddr = uaddr;
1295 fi->reply_data = NULL;
1296 (void) cond_init(&fi->cv, USYNC_THREAD, NULL);
1298 rpcb_rmtcalls++;
1299 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
1300 assert(fitail != fi);
1301 (void) cond_signal(&fitail->cv);
1304 return (fi);
1307 static void
1308 forward_destroy(struct finfo *fi)
1310 assert(MUTEX_HELD(&finfo_lock));
1311 assert(fi->flag & FINFO_ACTIVE);
1313 if (fihead == fi) {
1314 assert(fi->prev == NULL);
1315 fihead = fi->next;
1316 } else {
1317 fi->prev->next = fi->next;
1320 if (fitail == fi) {
1321 assert(fi->next == NULL);
1322 fitail = fi->prev;
1323 } else {
1324 fi->next->prev = fi->prev;
1327 netbuffree(fi->caller_addr);
1328 free(fi->uaddr);
1329 if (fi->reply_data != NULL)
1330 t_free((char *)fi->reply_data, T_UNITDATA);
1331 (void) cond_destroy(&fi->cv);
1333 free(fi);
1335 rpcb_rmtcalls--;
1336 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
1337 assert(fitail != NULL);
1338 (void) cond_signal(&fitail->cv);
1342 static struct finfo *
1343 forward_find(ulong_t reply_xid, char *uaddr)
1345 struct finfo *fi;
1347 assert(MUTEX_HELD(&finfo_lock));
1349 for (fi = fihead; fi != NULL; fi = fi->next) {
1350 if (fi->forward_xid == reply_xid &&
1351 strcmp(fi->uaddr, uaddr) == 0)
1352 return (fi);
1355 return (NULL);
1358 static int
1359 netbufcmp(struct netbuf *n1, struct netbuf *n2)
1361 return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1364 static struct netbuf *
1365 netbufdup(struct netbuf *ap)
1367 struct netbuf *np;
1369 np = malloc(sizeof (struct netbuf) + ap->len);
1370 if (np) {
1371 np->maxlen = np->len = ap->len;
1372 np->buf = ((char *)np) + sizeof (struct netbuf);
1373 (void) memcpy(np->buf, ap->buf, ap->len);
1375 return (np);
1378 static void
1379 netbuffree(struct netbuf *ap)
1381 free(ap);
1384 static void
1385 handle_reply(svc_input_id_t id, int fd, unsigned int events, void *cookie)
1387 struct t_unitdata *tr_data;
1388 int res;
1390 unsigned int inlen;
1391 char *buffer;
1392 XDR reply_xdrs;
1394 struct rpc_msg reply_msg;
1395 unsigned int pos;
1396 unsigned int len;
1398 struct netconfig *nconf;
1399 char *uaddr = NULL;
1401 struct finfo *fi;
1403 tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
1404 T_ADDR | T_UDATA);
1405 if (tr_data == NULL) {
1406 syslog(LOG_ERR, "handle_reply: t_alloc failed!");
1407 return;
1410 do {
1411 int moreflag = 0;
1413 if (errno == EINTR)
1414 errno = 0;
1415 res = t_rcvudata(fd, tr_data, &moreflag);
1416 if (moreflag & T_MORE) {
1417 /* Drop this packet - we have no more space. */
1418 if (debugging)
1419 fprintf(stderr, "handle_reply: recvd packet "
1420 "with T_MORE flag set\n");
1421 goto done;
1423 } while (res < 0 && t_errno == TSYSERR && errno == EINTR);
1425 if (res < 0) {
1426 if (debugging)
1427 fprintf(stderr, "handle_reply: t_rcvudata returned "
1428 "%d, t_errno %d, errno %d\n", res, t_errno, errno);
1430 if (t_errno == TLOOK)
1431 (void) t_rcvuderr(fd, NULL);
1433 goto done;
1436 inlen = tr_data->udata.len;
1437 buffer = tr_data->udata.buf;
1438 assert(buffer != NULL);
1439 xdrmem_create(&reply_xdrs, buffer, inlen, XDR_DECODE);
1441 reply_msg.acpted_rply.ar_verf = _null_auth;
1442 reply_msg.acpted_rply.ar_results.where = 0;
1443 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
1445 if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1446 xdr_destroy(&reply_xdrs);
1447 if (debugging)
1448 (void) fprintf(stderr,
1449 "handle_reply: xdr_replymsg failed\n");
1450 goto done;
1452 pos = XDR_GETPOS(&reply_xdrs);
1453 xdr_destroy(&reply_xdrs);
1455 len = inlen - pos;
1457 nconf = rpcbind_get_conf((char *)cookie);
1458 if (nconf == NULL) {
1459 syslog(LOG_ERR, "handle_reply: rpcbind_get_conf failed!");
1460 goto done;
1462 uaddr = taddr2uaddr(nconf, &tr_data->addr);
1463 if (uaddr == NULL) {
1464 syslog(LOG_ERR, "handle_reply: taddr2uaddr failed!");
1465 goto done;
1468 (void) mutex_lock(&finfo_lock);
1469 fi = forward_find(reply_msg.rm_xid, uaddr);
1470 if (fi == NULL) {
1471 (void) mutex_unlock(&finfo_lock);
1472 goto done;
1475 fi->reply_data = tr_data;
1476 tr_data = NULL;
1478 __seterr_reply(&reply_msg, &fi->reply_error);
1480 fi->res_len = len;
1481 fi->res_val = &buffer[pos];
1483 (void) cond_signal(&fi->cv);
1484 (void) mutex_unlock(&finfo_lock);
1486 done:
1487 free(uaddr);
1488 if (tr_data)
1489 t_free((char *)tr_data, T_UNITDATA);
1493 * prog: Program Number
1494 * netid: Transport Provider token
1495 * lowvp: Low version number
1496 * highvp: High version number
1498 static void
1499 find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
1501 rpcblist_ptr rbl;
1502 rpcvers_t lowv = 0;
1503 rpcvers_t highv = 0;
1505 assert(RW_LOCK_HELD(&list_rbl_lock));
1507 for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1508 if ((rbl->rpcb_map.r_prog != prog) ||
1509 (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
1510 continue;
1511 if (lowv == 0) {
1512 highv = rbl->rpcb_map.r_vers;
1513 lowv = highv;
1514 } else if (rbl->rpcb_map.r_vers < lowv) {
1515 lowv = rbl->rpcb_map.r_vers;
1516 } else if (rbl->rpcb_map.r_vers > highv) {
1517 highv = rbl->rpcb_map.r_vers;
1521 *lowvp = lowv;
1522 *highvp = highv;
1526 * returns the item with the given program, version number and netid.
1527 * If that version number is not found, it returns the item with that
1528 * program number, so that address is now returned to the caller. The
1529 * caller when makes a call to this program, version number, the call
1530 * will fail and it will return with PROGVERS_MISMATCH. The user can
1531 * then determine the highest and the lowest version number for this
1532 * program using clnt_geterr() and use those program version numbers.
1534 * Returns the RPCBLIST for the given prog, vers and netid
1536 * prog: Program Number
1537 * vers: Version Number
1538 * netid: Transport Provider token
1540 static rpcblist_ptr
1541 find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
1543 rpcblist_ptr hit = NULL;
1544 rpcblist_ptr rbl;
1546 assert(RW_LOCK_HELD(&list_rbl_lock));
1548 for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1549 if ((rbl->rpcb_map.r_prog != prog) ||
1550 (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
1551 continue;
1552 hit = rbl;
1553 if (rbl->rpcb_map.r_vers == vers)
1554 break;
1557 return (hit);
1561 * If the caller is from our zone and we know
1562 * who it is, we return the uid.
1564 uid_t
1565 rpcb_caller_uid(SVCXPRT *transp)
1567 ucred_t *uc = alloca(ucred_size());
1569 if (svc_getcallerucred(transp, &uc) != 0 ||
1570 (ucred_getzoneid(uc)) != myzone) {
1571 return (-1);
1572 } else {
1573 return (ucred_geteuid(uc));
1578 * Copies the name associated with the uid of the caller and returns
1579 * a pointer to it. Similar to getwd().
1581 char *
1582 getowner(SVCXPRT *transp, char *owner)
1584 uid_t uid = rpcb_caller_uid(transp);
1586 switch (uid) {
1587 case -1:
1588 return (strcpy(owner, "unknown"));
1589 case 0:
1590 return (strcpy(owner, "superuser"));
1591 default:
1592 (void) sprintf(owner, "%u", uid);
1593 return (owner);
1597 #ifdef PORTMAP
1599 * Add this to the pmap list only if it is UDP or TCP.
1601 static int
1602 add_pmaplist(RPCB *arg)
1604 pmap pmap;
1605 pmaplist *pml;
1606 int h1, h2, h3, h4, p1, p2;
1608 if (strcmp(arg->r_netid, udptrans) == 0) {
1609 /* It is UDP! */
1610 pmap.pm_prot = IPPROTO_UDP;
1611 } else if (strcmp(arg->r_netid, tcptrans) == 0) {
1612 /* It is TCP */
1613 pmap.pm_prot = IPPROTO_TCP;
1614 } else
1615 /* Not a IP protocol */
1616 return (0);
1618 /* interpret the universal address for TCP/IP */
1619 if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1620 &h1, &h2, &h3, &h4, &p1, &p2) != 6)
1621 return (0);
1622 pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1623 pmap.pm_prog = arg->r_prog;
1624 pmap.pm_vers = arg->r_vers;
1626 * add to END of list
1628 pml = (pmaplist *) malloc((uint_t)sizeof (pmaplist));
1629 if (pml == NULL) {
1630 (void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1631 return (1);
1633 pml->pml_map = pmap;
1634 pml->pml_next = NULL;
1636 (void) rw_wrlock(&list_pml_lock);
1637 if (list_pml == NULL) {
1638 list_pml = pml;
1639 } else {
1640 pmaplist *fnd;
1642 /* Attach to the end of the list */
1643 for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1645 fnd->pml_next = pml;
1647 (void) rw_unlock(&list_pml_lock);
1649 return (0);
1653 * Delete this from the pmap list only if it is UDP or TCP.
1656 del_pmaplist(RPCB *arg)
1658 pmaplist *pml;
1659 pmaplist *prevpml, *fnd;
1660 rpcport_t prot;
1662 if (strcmp(arg->r_netid, udptrans) == 0) {
1663 /* It is UDP! */
1664 prot = IPPROTO_UDP;
1665 } else if (strcmp(arg->r_netid, tcptrans) == 0) {
1666 /* It is TCP */
1667 prot = IPPROTO_TCP;
1668 } else if (arg->r_netid[0] == '\0') {
1669 prot = 0; /* Remove all occurrences */
1670 } else {
1671 /* Not a IP protocol */
1672 return (0);
1675 assert(RW_WRITE_HELD(&list_pml_lock));
1677 for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1678 if ((pml->pml_map.pm_prog != arg->r_prog) ||
1679 (pml->pml_map.pm_vers != arg->r_vers) ||
1680 (prot && (pml->pml_map.pm_prot != prot))) {
1681 /* both pml & prevpml move forwards */
1682 prevpml = pml;
1683 pml = pml->pml_next;
1684 continue;
1686 /* found it; pml moves forward, prevpml stays */
1687 fnd = pml;
1688 pml = pml->pml_next;
1689 if (prevpml == NULL)
1690 list_pml = pml;
1691 else
1692 prevpml->pml_next = pml;
1693 free(fnd);
1696 return (0);
1698 #endif /* PORTMAP */