4908 rpcbind NULL ptr dereference at forward_destroy+0x22()
[unleashed.git] / usr / src / cmd / rpcbind / rpcb_svc_com.c
blob0d2684f0a7d0e419db92ae377dc10ce4d28bc25e
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.
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
41 * rpcb_svc_com.c
42 * The commom server procedure for the rpcbind.
45 #include <stdio.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <strings.h>
52 #include <rpc/rpc.h>
53 #include <rpc/rpcb_prot.h>
54 #include <rpcsvc/svc_dg_priv.h>
55 #include <netconfig.h>
56 #include <sys/param.h>
57 #include <errno.h>
58 #include <zone.h>
59 #include <sys/poll.h>
60 #include <sys/stropts.h>
61 #ifdef PORTMAP
62 #include <netinet/in.h>
63 #include <rpc/pmap_prot.h>
64 #else
65 #define PMAPVERS 2
66 #endif /* PORTMAP */
67 #include <syslog.h>
68 #include <netdir.h>
69 #include <ucred.h>
70 #include <alloca.h>
71 #include <rpcsvc/yp_prot.h>
72 #include <nfs/nfs.h>
73 #include <nfs/nfs_acl.h>
74 #include <rpcsvc/mount.h>
75 #include <nfs/nfs_acl.h>
76 #include <rpc/key_prot.h>
77 #include <rpcsvc/yp_prot.h>
78 #include <rpcsvc/rquota.h>
79 #include <rpcsvc/yppasswd.h>
80 #include <rpcsvc/ypupd.h>
81 #include <assert.h>
82 #include <synch.h>
83 #include "rpcbind.h"
85 static struct finfo *forward_register(ulong_t, struct netbuf *, int, char *);
86 static void forward_destroy(struct finfo *);
87 static void handle_reply(svc_input_id_t, int, unsigned int, void *);
88 static int netbufcmp(struct netbuf *, struct netbuf *);
89 static void netbuffree(struct netbuf *);
90 static struct netbuf *netbufdup(struct netbuf *);
91 static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
92 static rpcblist_ptr find_service(ulong_t, ulong_t, char *);
93 #ifdef PORTMAP
94 static int add_pmaplist(RPCB *);
95 #endif
97 zoneid_t myzone;
100 * Set a mapping of program, version, netid
102 bool_t
103 rpcbproc_set_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
104 int rpcbversnum)
106 char owner[64];
108 *result = map_set(regp, getowner(rqstp->rq_xprt, owner));
110 rpcbs_set(rpcbversnum - PMAPVERS, *result);
112 return (TRUE);
115 bool_t
116 map_set(RPCB *regp, char *owner)
118 RPCB *a;
119 rpcblist_ptr rbl, fnd;
122 * check to see if already used
123 * find_service returns a hit even if
124 * the versions don't match, so check for it
126 (void) rw_wrlock(&list_rbl_lock);
127 #ifdef PORTMAP
128 (void) rw_wrlock(&list_pml_lock);
129 #endif /* PORTMAP */
130 fnd = find_service(regp->r_prog, regp->r_vers, regp->r_netid);
131 if (fnd && (fnd->rpcb_map.r_vers == regp->r_vers)) {
132 if (strcmp(fnd->rpcb_map.r_addr, regp->r_addr) == 0) {
134 * if these match then it is already
135 * registered so just say "OK".
137 #ifdef PORTMAP
138 (void) rw_unlock(&list_pml_lock);
139 #endif /* PORTMAP */
140 (void) rw_unlock(&list_rbl_lock);
141 return (TRUE);
142 } else {
144 * Check if server is up. If so, return FALSE.
145 * If not, cleanup old registrations for the
146 * program and register the new server.
148 if (is_bound(fnd->rpcb_map.r_netid,
149 fnd->rpcb_map.r_addr)) {
150 #ifdef PORTMAP
151 (void) rw_unlock(&list_pml_lock);
152 #endif /* PORTMAP */
153 (void) rw_unlock(&list_rbl_lock);
154 return (FALSE);
157 delete_prog(regp->r_prog);
158 fnd = NULL;
161 #ifdef PORTMAP
162 (void) rw_unlock(&list_pml_lock);
163 #endif /* PORTMAP */
166 * add to the end of the list
168 rbl = malloc(sizeof (RPCBLIST));
169 if (rbl == NULL) {
170 (void) rw_unlock(&list_rbl_lock);
171 return (FALSE);
173 a = &rbl->rpcb_map;
174 a->r_prog = regp->r_prog;
175 a->r_vers = regp->r_vers;
176 a->r_netid = strdup(regp->r_netid);
177 a->r_addr = strdup(regp->r_addr);
178 a->r_owner = strdup(owner);
179 if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
180 (void) rw_unlock(&list_rbl_lock);
181 delete_rbl(rbl);
182 return (FALSE);
184 rbl->rpcb_next = NULL;
185 if (list_rbl == NULL) {
186 list_rbl = rbl;
187 } else {
188 for (fnd = list_rbl; fnd->rpcb_next; fnd = fnd->rpcb_next)
190 fnd->rpcb_next = rbl;
193 #ifdef PORTMAP
194 (void) add_pmaplist(regp);
195 #endif
196 (void) rw_unlock(&list_rbl_lock);
197 return (TRUE);
201 * Unset a mapping of program, version, netid
203 bool_t
204 rpcbproc_unset_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
205 int rpcbversnum)
207 char owner[64];
209 *result = map_unset(regp, getowner(rqstp->rq_xprt, owner));
211 rpcbs_unset(rpcbversnum - PMAPVERS, *result);
213 return (TRUE);
216 bool_t
217 map_unset(RPCB *regp, char *owner)
219 #ifdef PORTMAP
220 int ans = 0;
221 #endif
222 rpcblist_ptr rbl, next, prev = NULL;
224 if (owner == NULL)
225 return (0);
227 (void) rw_wrlock(&list_rbl_lock);
228 for (rbl = list_rbl; rbl != NULL; rbl = next) {
229 next = rbl->rpcb_next;
231 if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
232 (rbl->rpcb_map.r_vers != regp->r_vers) ||
233 (regp->r_netid[0] && strcasecmp(regp->r_netid,
234 rbl->rpcb_map.r_netid))) {
235 /* prev moves forwards */
236 prev = rbl;
237 continue;
241 * Check whether appropriate uid. Unset only
242 * if superuser or the owner itself.
244 if (strcmp(owner, "superuser") &&
245 strcmp(rbl->rpcb_map.r_owner, owner)) {
246 (void) rw_unlock(&list_rbl_lock);
247 return (0);
250 /* prev stays */
251 #ifdef PORTMAP
252 ans = 1;
253 #endif
254 delete_rbl(rbl);
256 if (prev == NULL)
257 list_rbl = next;
258 else
259 prev->rpcb_next = next;
261 #ifdef PORTMAP
262 if (ans != 0) {
263 (void) rw_wrlock(&list_pml_lock);
264 (void) del_pmaplist(regp);
265 (void) rw_unlock(&list_pml_lock);
267 #endif
268 (void) rw_unlock(&list_rbl_lock);
271 * We return 1 either when the entry was not there or it
272 * was able to unset it. It can come to this point only if
273 * at least one of the conditions is true.
275 return (1);
278 void
279 delete_rbl(rpcblist_ptr rbl)
281 free(rbl->rpcb_map.r_addr);
282 free(rbl->rpcb_map.r_netid);
283 free(rbl->rpcb_map.r_owner);
284 free(rbl);
287 void
288 delete_prog(rpcprog_t prog)
290 rpcblist_ptr rbl, next, prev = NULL;
292 assert(RW_WRITE_HELD(&list_rbl_lock));
294 for (rbl = list_rbl; rbl != NULL; rbl = next) {
295 next = rbl->rpcb_next;
297 if (rbl->rpcb_map.r_prog != prog ||
298 is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) {
299 prev = rbl;
300 continue;
303 #ifdef PORTMAP
304 (void) del_pmaplist(&rbl->rpcb_map);
305 #endif
306 delete_rbl(rbl);
308 if (prev == NULL)
309 list_rbl = next;
310 else
311 prev->rpcb_next = next;
316 * Lookup the mapping for a program, version and return its
317 * address. Assuming that the caller wants the address of the
318 * server running on the transport on which the request came.
320 * For RPCBPROC_GETVERSADDR it will return a service with the exact version
321 * number only.
323 * Otherwise, even if a service with a different version number is available,
324 * it will return that address. The client should check with an
325 * clnt_call to verify whether the service is the one that is desired.
327 * We also try to resolve the universal address in terms of
328 * address of the caller.
330 bool_t
331 rpcbproc_getaddr_com(RPCB *regp, char **result, struct svc_req *rqstp,
332 ulong_t rpcbversnum)
334 char *saddr = NULL;
335 rpcblist_ptr fnd;
336 struct netconfig *trans_conf; /* transport netconfig */
337 SVCXPRT *transp = rqstp->rq_xprt;
338 int verstype = rqstp->rq_proc == RPCBPROC_GETVERSADDR ? RPCB_ONEVERS :
339 RPCB_ALLVERS;
340 bool_t pml_locked = FALSE;
343 * There is a potential window at startup during which rpcbind
344 * service has been established over IPv6 but not over IPv4. If an
345 * IPv4 request comes in during that window, the IP code will map
346 * it into IPv6. We could patch up the request so that it looks
347 * like IPv4 (so that rpcbind returns an IPv4 uaddr to the caller),
348 * but that requires some non-trivial code and it's hard to test.
349 * Instead, drop the request on the floor and force the caller to
350 * retransmit. By the time rpcbind sees the retransmission, IPv4
351 * service should be in place and it should see the request as
352 * IPv4, as desired.
354 trans_conf = rpcbind_get_conf(transp->xp_netid);
355 if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) {
356 struct sockaddr_in6 *rmtaddr;
358 rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
359 if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
360 syslog(LOG_DEBUG,
361 "IPv4 GETADDR request mapped to IPv6: ignoring");
362 *result = NULL;
363 return (FALSE);
367 (void) rw_rdlock(&list_rbl_lock);
368 retry:
369 fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
370 if (fnd && ((verstype == RPCB_ALLVERS) ||
371 (regp->r_vers == fnd->rpcb_map.r_vers))) {
372 if (*(regp->r_addr) != '\0') { /* may contain a hint about */
373 saddr = regp->r_addr; /* the interface that we */
374 } /* should use */
375 if (!(*result = mergeaddr(transp, transp->xp_netid,
376 fnd->rpcb_map.r_addr, saddr))) {
377 /* Try whatever we have */
378 *result = strdup(fnd->rpcb_map.r_addr);
379 } else if (!(*result)[0]) {
380 if (!pml_locked) {
381 (void) rw_unlock(&list_rbl_lock);
382 (void) rw_wrlock(&list_rbl_lock);
383 #ifdef PORTMAP
384 (void) rw_wrlock(&list_pml_lock);
385 #endif /* PORTMAP */
386 pml_locked = TRUE;
387 goto retry;
390 * The server died. Unset all versions of this prog.
392 delete_prog(regp->r_prog);
393 *result = NULL;
395 } else {
396 *result = NULL;
398 #ifdef PORTMAP
399 if (pml_locked)
400 (void) rw_unlock(&list_pml_lock);
401 #endif /* PORTMAP */
402 (void) rw_unlock(&list_rbl_lock);
404 rpcbs_getaddr(rpcbversnum - PMAPVERS, regp->r_prog, regp->r_vers,
405 transp->xp_netid, *result);
406 return (TRUE);
409 /* ARGSUSED */
410 bool_t
411 rpcbproc_dump_com(void *argp, rpcblist_ptr **result)
414 * list_rbl_lock is unlocked in xdr_rpcblist_ptr_ptr()
416 (void) rw_rdlock(&list_rbl_lock);
417 *result = &list_rbl;
418 return (TRUE);
421 bool_t
422 xdr_rpcblist_ptr_ptr(XDR *xdrs, rpcblist_ptr **objp)
424 if (xdrs->x_op == XDR_FREE) {
426 * list_rbl_lock is locked in rpcbproc_dump_com()
428 rw_unlock(&list_rbl_lock);
429 return (TRUE);
432 return (xdr_rpcblist_ptr(xdrs, *objp));
435 /* ARGSUSED */
436 bool_t
437 rpcbproc_gettime_com(void *argp, ulong_t *result)
439 (void) time((time_t *)result);
441 return (TRUE);
445 * Convert uaddr to taddr. Should be used only by
446 * local servers/clients. (kernel level stuff only)
448 bool_t
449 rpcbproc_uaddr2taddr_com(char **uaddrp, struct netbuf *result,
450 struct svc_req *rqstp)
452 struct netconfig *nconf;
453 struct netbuf *taddr;
455 if (((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL) ||
456 ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
457 (void) memset(result, 0, sizeof (*result));
458 return (TRUE);
461 memcpy(result, taddr, sizeof (*result));
462 free(taddr);
464 return (TRUE);
468 * Convert taddr to uaddr. Should be used only by
469 * local servers/clients. (kernel level stuff only)
471 bool_t
472 rpcbproc_taddr2uaddr_com(struct netbuf *taddr, char **result,
473 struct svc_req *rqstp)
475 struct netconfig *nconf;
477 if ((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL)
478 *result = NULL;
479 else
480 *result = taddr2uaddr(nconf, taddr);
482 return (TRUE);
486 * Stuff for the rmtcall service
488 bool_t
489 xdr_rpcb_rmtcallargs(XDR *xdrs, rpcb_rmtcallargs *objp)
491 if (!xdr_u_long(xdrs, &objp->prog))
492 return (FALSE);
493 if (!xdr_u_long(xdrs, &objp->vers))
494 return (FALSE);
495 if (!xdr_u_long(xdrs, &objp->proc))
496 return (FALSE);
497 if (!xdr_bytes(xdrs, (char **)&objp->args.args_val,
498 (uint_t *)&objp->args.args_len, ~0))
499 return (FALSE);
500 return (TRUE);
503 #ifdef PORTMAP
504 bool_t
505 xdr_rmtcallres(XDR *xdrs, rmtcallres *objp)
507 if (!xdr_u_long(xdrs, &objp->port))
508 return (FALSE);
509 if (!xdr_bytes(xdrs, (char **)&objp->res.res_val,
510 (uint_t *)&objp->res.res_len, ~0))
511 return (FALSE);
512 return (TRUE);
514 #endif
516 bool_t
517 xdr_rpcb_rmtcallres(XDR *xdrs, rpcb_rmtcallres *objp)
519 if (!xdr_string(xdrs, &objp->addr, ~0))
520 return (FALSE);
521 if (!xdr_bytes(xdrs, (char **)&objp->results.results_val,
522 (uint_t *)&objp->results.results_len, ~0))
523 return (FALSE);
524 return (TRUE);
527 struct rmtcallfd_list {
528 int fd;
529 char *netid;
530 struct rmtcallfd_list *next;
533 static struct rmtcallfd_list *rmthead;
534 static struct rmtcallfd_list *rmttail;
536 #define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
539 create_rmtcall_fd(struct netconfig *nconf)
541 int fd;
542 struct rmtcallfd_list *rmt;
544 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
545 if (debugging)
546 fprintf(stderr, "create_rmtcall_fd: couldn't open "
547 "\"%s\" (errno %d, t_errno %d)\n",
548 nconf->nc_device, errno, t_errno);
549 return (-1);
552 if (t_bind(fd, NULL, NULL) == -1) {
553 if (debugging)
554 fprintf(stderr, "create_rmtcall_fd: couldn't bind to "
555 "fd for \"%s\" (errno %d, t_errno %d)\n",
556 nconf->nc_device, errno, t_errno);
557 return (-1);
560 rmt = malloc(sizeof (struct rmtcallfd_list));
561 if (rmt == NULL) {
562 syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
563 return (-1);
566 rmt->netid = strdup(nconf->nc_netid);
567 if (rmt->netid == NULL) {
568 free(rmt);
569 syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
570 return (-1);
573 if (svc_add_input(fd, MASKVAL, handle_reply, rmt->netid) == -1) {
574 free(rmt->netid);
575 free(rmt);
576 syslog(LOG_ERR, "create_rmtcall_fd: svc_add_input() failed!");
577 return (-1);
580 rmt->fd = fd;
581 rmt->next = NULL;
582 if (rmthead == NULL) {
583 rmthead = rmt;
584 rmttail = rmt;
585 } else {
586 rmttail->next = rmt;
587 rmttail = rmt;
590 return (fd);
593 static int
594 find_rmtcallfd_by_netid(char *netid)
596 struct rmtcallfd_list *rmt;
598 for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
599 if (strcmp(netid, rmt->netid) == 0) {
600 return (rmt->fd);
603 return (-1);
606 #define MAXTIME_OFF 300 /* 5 minutes timeout for rmtcalls */
608 struct finfo {
609 struct finfo *prev;
610 struct finfo *next;
611 int flag;
612 #define FINFO_ACTIVE 0x1
613 ulong_t caller_xid;
614 struct netbuf *caller_addr;
615 ulong_t forward_xid;
616 int forward_fd;
617 char *uaddr;
618 struct t_unitdata *reply_data;
619 struct rpc_err reply_error;
620 uint_t res_len;
621 void *res_val;
622 cond_t cv;
626 * finfo_lock protects rpcb_rmtcalls, rpcb_rmtcalls_max, lastxid,
627 * fihead, and fitail.
629 static mutex_t finfo_lock = DEFAULTMUTEX;
631 static int rpcb_rmtcalls;
632 static int rpcb_rmtcalls_max;
633 static ulong_t lastxid;
634 static struct finfo *fihead;
635 static struct finfo *fitail;
637 void
638 set_rpcb_rmtcalls_max(int max)
640 (void) mutex_lock(&finfo_lock);
641 rpcb_rmtcalls_max = max;
642 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
643 assert(fitail != NULL);
644 (void) cond_signal(&fitail->cv);
646 (void) mutex_unlock(&finfo_lock);
650 * Call a remote procedure service. This procedure is very quiet when things
651 * go wrong. The proc is written to support broadcast rpc. In the broadcast
652 * case, a machine should shut-up instead of complain, lest the requestor be
653 * overrun with complaints at the expense of not hearing a valid reply.
654 * When receiving a request and verifying that the service exists, we
656 * receive the request
658 * open a new TLI endpoint on the same transport on which we received
659 * the original request
661 * remember the original request's XID (which requires knowing the format
662 * of the svc_dg_data structure)
664 * forward the request, with a new XID, to the requested service,
665 * remembering the XID used to send this request (for later use in
666 * reassociating the answer with the original request), the requestor's
667 * address, the file descriptor on which the forwarded request is
668 * made and the service's address
670 * wait for either the timeout or the condition variable is signalled from
671 * handle_reply().
673 * At some time in the future, a reply will be received from the service to
674 * which we forwarded the request. At that time, svc_run() detect that the
675 * socket used was for forwarding and call handle_reply() to
677 * receive the reply
679 * bundle the reply, along with the service's universal address
681 * put the reply into the particular finfo
683 * signal the condition variable.
686 #define RPC_BUF_MAX 65536 /* can be raised if required */
689 * This is from ../ypcmd/yp_b.h
690 * It does not appear in <rpcsvc/yp_prot.h>
692 #define YPBINDPROG ((ulong_t)100007)
693 #define YPBINDPROC_SETDOM ((ulong_t)2)
696 * reply_type - which proc number
697 * versnum - which vers was called
699 void
700 rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp, ulong_t reply_type,
701 int versnum)
703 struct t_info tinfo;
704 uint_t sendsz;
706 rpcb_rmtcallargs arg;
707 rpcblist_ptr rbl;
709 struct netconfig *nconf;
710 struct netbuf *caller;
711 struct nd_mergearg ma;
712 int stat;
714 int fd;
715 struct svc_dg_data *bd;
716 struct finfo *fi;
718 struct rpc_msg call_msg;
719 char outbuf[RPC_BUF_MAX];
720 char *outbuf_alloc = NULL;
721 XDR outxdr;
722 bool_t outxdr_created = FALSE;
724 AUTH *auth;
726 struct t_unitdata tu_data;
727 struct netbuf *na;
729 timestruc_t to;
731 (void) mutex_lock(&finfo_lock);
732 if (!allow_indirect || rpcb_rmtcalls_max == 0) {
733 (void) mutex_unlock(&finfo_lock);
734 return;
736 (void) mutex_unlock(&finfo_lock);
738 if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
739 if (reply_type == RPCBPROC_INDIRECT)
740 svcerr_systemerr(transp);
741 return;
743 if (tinfo.servtype != T_CLTS)
744 return; /* Only datagram type accepted */
746 sendsz = __rpc_get_t_size(0, tinfo.tsdu);
747 if (sendsz == 0) { /* data transfer not supported */
748 if (reply_type == RPCBPROC_INDIRECT)
749 svcerr_systemerr(transp);
750 return;
753 * Should be multiple of 4 for XDR.
755 sendsz = ((sendsz + 3) / 4) * 4;
757 (void) memset((char *)&arg, 0, sizeof (arg));
758 if (!svc_getargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg)) {
759 if (reply_type == RPCBPROC_INDIRECT)
760 svcerr_decode(transp);
761 if (debugging)
762 fprintf(stderr,
763 "rpcbproc_callit_com: svc_getargs failed\n");
764 goto error;
768 * Disallow calling rpcbind for certain procedures.
769 * Allow calling NULLPROC - per man page on rpcb_rmtcall().
770 * switch is in alphabetical order.
772 if (arg.proc != NULLPROC) {
773 switch (arg.prog) {
774 case KEY_PROG:
775 if (debugging)
776 fprintf(stderr,
777 "rpcbind: rejecting KEY_PROG(%d)\n",
778 arg.proc);
779 goto error;
780 case MOUNTPROG:
781 if (arg.proc != MOUNTPROC_MNT)
782 break;
784 * In Solaris 2.6, the host-based accesss control
785 * is done by the NFS server on each request.
786 * Prior to 2.6 we rely on mountd.
788 if (debugging)
789 fprintf(stderr,
790 "rpcbind: rejecting MOUNTPROG(%d)\n",
791 arg.proc);
792 goto error;
793 case NFS_ACL_PROGRAM:
794 if (debugging)
795 fprintf(stderr,
796 "rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
797 arg.proc);
798 goto error;
799 case NFS_PROGRAM:
800 /* also NFS3_PROGRAM */
801 if (debugging)
802 fprintf(stderr,
803 "rpcbind: rejecting NFS_PROGRAM(%d)\n",
804 arg.proc);
805 goto error;
806 case RPCBPROG:
808 * Disallow calling rpcbind for certain procedures.
809 * Luckily Portmap set/unset/callit also have same
810 * procedure numbers. So, will not check for those.
812 switch (arg.proc) {
813 case RPCBPROC_SET:
814 case RPCBPROC_UNSET:
815 case RPCBPROC_CALLIT:
816 case RPCBPROC_INDIRECT:
817 if (reply_type == RPCBPROC_INDIRECT)
818 svcerr_weakauth(transp); /* XXX */
819 if (debugging)
820 fprintf(stderr, "rpcbproc_callit_com: "
821 "calling RPCBPROG procs SET, "
822 "UNSET, CALLIT, or INDIRECT not "
823 "allowed\n");
824 goto error;
825 default:
827 * Ideally, we should have called rpcb_service()
828 * or pmap_service() with appropriate parameters
829 * instead of going about in a roundabout
830 * manner. Hopefully, this case should happen
831 * rarely.
833 break;
835 break;
836 case RQUOTAPROG:
837 if (debugging)
838 fprintf(stderr,
839 "rpcbind: rejecting RQUOTAPROG(%d)\n",
840 arg.proc);
841 goto error;
842 case YPPASSWDPROG:
843 if (debugging)
844 fprintf(stderr,
845 "rpcbind: rejecting YPPASSWDPROG(%d)\n",
846 arg.proc);
847 goto error;
848 case YPU_PROG:
849 if (debugging)
850 fprintf(stderr,
851 "rpcbind: rejecting YPU_PROG(%d)\n",
852 arg.proc);
853 goto error;
854 case YPBINDPROG:
855 if (arg.proc != YPBINDPROC_SETDOM)
856 break;
857 if (debugging)
858 fprintf(stderr,
859 "rpcbind: rejecting YPBINDPROG(%d)\n",
860 arg.proc);
861 goto error;
862 case YPPROG:
863 switch (arg.proc) {
864 case YPPROC_FIRST:
865 case YPPROC_NEXT:
866 case YPPROC_MATCH:
867 case YPPROC_ALL:
868 if (debugging)
869 fprintf(stderr,
870 "rpcbind: rejecting YPPROG(%d)\n",
871 arg.proc);
872 goto error;
873 default:
874 break;
876 break;
877 default:
878 break;
882 (void) rw_rdlock(&list_rbl_lock);
883 rbl = find_service(arg.prog, arg.vers, transp->xp_netid);
885 rpcbs_rmtcall(versnum - PMAPVERS, reply_type, arg.prog, arg.vers,
886 arg.proc, transp->xp_netid, rbl);
888 if (rbl == NULL) {
889 (void) rw_unlock(&list_rbl_lock);
890 if (reply_type == RPCBPROC_INDIRECT)
891 svcerr_noprog(transp);
892 goto error;
894 if (rbl->rpcb_map.r_vers != arg.vers) {
895 if (reply_type == RPCBPROC_INDIRECT) {
896 ulong_t vers_low, vers_high;
898 find_versions(arg.prog, transp->xp_netid,
899 &vers_low, &vers_high);
900 (void) rw_unlock(&list_rbl_lock);
901 svcerr_progvers(transp, vers_low, vers_high);
902 } else {
903 (void) rw_unlock(&list_rbl_lock);
905 goto error;
909 * Check whether this entry is valid and a server is present
910 * Mergeaddr() returns NULL if no such entry is present, and
911 * returns "" if the entry was present but the server is not
912 * present (i.e., it crashed).
914 if (reply_type == RPCBPROC_INDIRECT) {
915 char *uaddr = mergeaddr(transp, transp->xp_netid,
916 rbl->rpcb_map.r_addr, NULL);
917 if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
918 (void) rw_unlock(&list_rbl_lock);
919 svcerr_noprog(transp);
920 goto error;
921 } else {
922 free(uaddr);
926 nconf = rpcbind_get_conf(transp->xp_netid);
927 if (nconf == NULL) {
928 (void) rw_unlock(&list_rbl_lock);
929 if (reply_type == RPCBPROC_INDIRECT)
930 svcerr_systemerr(transp);
931 if (debugging)
932 fprintf(stderr,
933 "rpcbproc_callit_com: rpcbind_get_conf failed\n");
934 goto error;
937 caller = svc_getrpccaller(transp);
938 ma.c_uaddr = taddr2uaddr(nconf, caller);
939 ma.s_uaddr = rbl->rpcb_map.r_addr;
942 * A mergeaddr operation allocates a string, which it stores in
943 * ma.m_uaddr. It's passed to forward_register() and is
944 * eventually freed by forward_destroy().
946 stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
947 (void) rw_unlock(&list_rbl_lock);
948 free(ma.c_uaddr);
949 if (stat)
950 (void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
951 nconf->nc_netid, netdir_sperror());
953 if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
954 if (reply_type == RPCBPROC_INDIRECT)
955 svcerr_systemerr(transp);
956 free(ma.m_uaddr);
957 goto error;
960 bd = get_svc_dg_data(transp);
962 assert(!MUTEX_HELD(&finfo_lock));
963 fi = forward_register(bd->su_xid, caller, fd, ma.m_uaddr);
964 if (fi == NULL) {
965 /* forward_register failed. Perhaps no memory. */
966 free(ma.m_uaddr);
967 if (debugging)
968 fprintf(stderr,
969 "rpcbproc_callit_com: forward_register failed\n");
970 assert(!MUTEX_HELD(&finfo_lock));
971 goto error;
973 /* forward_register() returns with finfo_lock held when successful */
974 assert(MUTEX_HELD(&finfo_lock));
976 if (fi->flag & FINFO_ACTIVE) {
978 * A duplicate request for the slow server. Let's not
979 * beat on it any more.
981 (void) mutex_unlock(&finfo_lock);
982 free(ma.m_uaddr);
983 if (debugging)
984 fprintf(stderr,
985 "rpcbproc_callit_com: duplicate request\n");
986 goto error;
988 fi->flag |= FINFO_ACTIVE;
990 call_msg.rm_xid = fi->forward_xid;
991 call_msg.rm_direction = CALL;
992 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
993 call_msg.rm_call.cb_prog = arg.prog;
994 call_msg.rm_call.cb_vers = arg.vers;
996 if (sendsz > RPC_BUF_MAX) {
997 outbuf_alloc = malloc(sendsz);
998 if (outbuf_alloc == NULL) {
999 forward_destroy(fi);
1000 (void) mutex_unlock(&finfo_lock);
1001 if (reply_type == RPCBPROC_INDIRECT)
1002 svcerr_systemerr(transp);
1003 if (debugging)
1004 fprintf(stderr,
1005 "rpcbproc_callit_com: No memory!\n");
1006 goto error;
1008 xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
1009 } else {
1010 xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
1012 outxdr_created = TRUE;
1014 if (!xdr_callhdr(&outxdr, &call_msg)) {
1015 forward_destroy(fi);
1016 (void) mutex_unlock(&finfo_lock);
1017 if (reply_type == RPCBPROC_INDIRECT)
1018 svcerr_systemerr(transp);
1019 if (debugging)
1020 fprintf(stderr,
1021 "rpcbproc_callit_com: xdr_callhdr failed\n");
1022 goto error;
1025 if (!xdr_u_long(&outxdr, &arg.proc)) {
1026 forward_destroy(fi);
1027 (void) mutex_unlock(&finfo_lock);
1028 if (reply_type == RPCBPROC_INDIRECT)
1029 svcerr_systemerr(transp);
1030 if (debugging)
1031 fprintf(stderr,
1032 "rpcbproc_callit_com: xdr_u_long failed\n");
1033 goto error;
1036 if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
1037 auth = authnone_create();
1038 } else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
1039 struct authsys_parms *au;
1041 au = (struct authsys_parms *)rqstp->rq_clntcred;
1042 auth = authsys_create(au->aup_machname, au->aup_uid,
1043 au->aup_gid, au->aup_len, au->aup_gids);
1044 if (auth == NULL) /* fall back */
1045 auth = authnone_create();
1046 } else {
1047 /* we do not support any other authentication scheme */
1048 forward_destroy(fi);
1049 (void) mutex_unlock(&finfo_lock);
1050 if (reply_type == RPCBPROC_INDIRECT)
1051 svcerr_weakauth(transp); /* XXX too strong.. */
1052 if (debugging)
1053 fprintf(stderr, "rpcbproc_callit_com: oa_flavor != "
1054 "AUTH_NONE and oa_flavor != AUTH_SYS\n");
1055 goto error;
1057 if (auth == NULL) {
1058 forward_destroy(fi);
1059 (void) mutex_unlock(&finfo_lock);
1060 if (reply_type == RPCBPROC_INDIRECT)
1061 svcerr_systemerr(transp);
1062 if (debugging)
1063 fprintf(stderr, "rpcbproc_callit_com: "
1064 "authwhatever_create returned NULL\n");
1065 goto error;
1067 if (!AUTH_MARSHALL(auth, &outxdr)) {
1068 forward_destroy(fi);
1069 (void) mutex_unlock(&finfo_lock);
1070 if (reply_type == RPCBPROC_INDIRECT)
1071 svcerr_systemerr(transp);
1072 AUTH_DESTROY(auth);
1073 if (debugging)
1074 fprintf(stderr,
1075 "rpcbproc_callit_com: AUTH_MARSHALL failed\n");
1076 goto error;
1078 AUTH_DESTROY(auth);
1080 if (!xdr_opaque(&outxdr, arg.args.args_val, arg.args.args_len)) {
1081 forward_destroy(fi);
1082 (void) mutex_unlock(&finfo_lock);
1083 if (reply_type == RPCBPROC_INDIRECT)
1084 svcerr_systemerr(transp);
1085 if (debugging)
1086 fprintf(stderr,
1087 "rpcbproc_callit_com: xdr_opaque failed\n");
1088 goto error;
1091 tu_data.udata.len = XDR_GETPOS(&outxdr);
1092 if (outbuf_alloc)
1093 tu_data.udata.buf = outbuf_alloc;
1094 else
1095 tu_data.udata.buf = outbuf;
1096 tu_data.opt.len = 0;
1098 na = uaddr2taddr(nconf, ma.m_uaddr);
1099 if (!na) {
1100 forward_destroy(fi);
1101 (void) mutex_unlock(&finfo_lock);
1102 if (reply_type == RPCBPROC_INDIRECT)
1103 svcerr_systemerr(transp);
1104 goto error;
1106 tu_data.addr = *na;
1108 if (t_sndudata(fd, &tu_data) == -1) {
1109 int err = errno;
1110 forward_destroy(fi);
1111 (void) mutex_unlock(&finfo_lock);
1113 netdir_free((char *)na, ND_ADDR);
1115 if (reply_type == RPCBPROC_INDIRECT)
1116 svcerr_systemerr(transp);
1117 if (debugging)
1118 fprintf(stderr,
1119 "rpcbproc_callit_com: t_sndudata failed: "
1120 "t_errno %d, errno %d\n", t_errno, err);
1121 goto error;
1124 netdir_free((char *)na, ND_ADDR);
1125 xdr_destroy(&outxdr);
1126 outxdr_created = FALSE;
1127 if (outbuf_alloc != NULL) {
1128 free(outbuf_alloc);
1129 outbuf_alloc = NULL;
1131 svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
1133 to.tv_sec = time(NULL) + MAXTIME_OFF;
1134 to.tv_nsec = 0;
1136 while (fi->reply_data == NULL &&
1137 cond_timedwait(&fi->cv, &finfo_lock, &to) != ETIME)
1140 if (fi->reply_data == NULL) {
1141 forward_destroy(fi);
1142 (void) mutex_unlock(&finfo_lock);
1144 if (reply_type == RPCBPROC_INDIRECT)
1145 svcerr_systemerr(transp);
1146 if (debugging)
1147 (void) fprintf(stderr,
1148 "rpcbproc_callit_com: timeout\n");
1149 return;
1152 if (fi->reply_error.re_status != RPC_SUCCESS) {
1153 forward_destroy(fi);
1154 (void) mutex_unlock(&finfo_lock);
1156 if (reply_type == RPCBPROC_INDIRECT)
1157 svcerr_systemerr(transp);
1158 if (debugging)
1159 (void) fprintf(stderr,
1160 "rpcbproc_callit_com: error in reply: %s\n",
1161 clnt_sperrno(fi->reply_error.re_status));
1162 return;
1165 switch (versnum) {
1166 #ifdef PORTMAP
1167 case PMAPVERS:
1169 rmtcallres result;
1170 int h1, h2, h3, h4, p1, p2;
1172 /* interpret the universal address for TCP/IP */
1173 if (sscanf(fi->uaddr, "%d.%d.%d.%d.%d.%d",
1174 &h1, &h2, &h3, &h4, &p1, &p2) != 6)
1175 break;
1177 result.port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1178 result.res.res_len = fi->res_len;
1179 result.res.res_val = fi->res_val;
1181 svc_sendreply(transp, xdr_rmtcallres, (char *)&result);
1183 break;
1184 #endif
1185 case RPCBVERS:
1186 case RPCBVERS4:
1188 rpcb_rmtcallres result;
1190 result.addr = fi->uaddr;
1191 result.results.results_len = fi->res_len;
1192 result.results.results_val = fi->res_val;
1194 svc_sendreply(transp, xdr_rpcb_rmtcallres,
1195 (char *)&result);
1197 break;
1200 forward_destroy(fi);
1201 (void) mutex_unlock(&finfo_lock);
1203 return;
1205 error:
1206 if (outxdr_created)
1207 xdr_destroy(&outxdr);
1208 free(outbuf_alloc);
1209 svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
1212 static struct finfo *forward_find(ulong_t, char *);
1215 * Adds an entry into the finfo list for the given request. Returns the finfo
1216 * and finfo_lock is left held. If duplicate request, returns finfo with
1217 * FINFO_ACTIVE, else returns finfo without FINFO_ACTIVE.
1218 * If failed, returns NULL and finfo_lock is left unheld.
1220 static struct finfo *
1221 forward_register(ulong_t caller_xid, struct netbuf *caller_addr, int forward_fd,
1222 char *uaddr)
1224 struct finfo *fi;
1226 (void) mutex_lock(&finfo_lock);
1227 if (rpcb_rmtcalls_max == 0) {
1228 (void) mutex_unlock(&finfo_lock);
1229 return (NULL);
1233 * initialization: once this has happened, lastxid will
1234 * never be 0 again, when entering or returning from this function.
1236 if (lastxid == 0)
1237 lastxid = time(NULL);
1240 * Check if it is an duplicate entry
1242 for (fi = fihead; fi != NULL; fi = fi->next) {
1243 if (fi->caller_xid == caller_xid &&
1244 netbufcmp(fi->caller_addr, caller_addr)) {
1245 assert(fi->flag & FINFO_ACTIVE);
1246 return (fi);
1250 fi = malloc(sizeof (*fi));
1251 if (fi == NULL) {
1252 (void) mutex_unlock(&finfo_lock);
1253 return (NULL);
1256 if ((fi->caller_addr = netbufdup(caller_addr)) == NULL) {
1257 (void) mutex_unlock(&finfo_lock);
1258 free(fi);
1259 return (NULL);
1263 * Generate new xid and make sure it is unique.
1265 do {
1266 lastxid++;
1267 /* avoid lastxid wraparound to 0 */
1268 if (lastxid == 0)
1269 lastxid = 1;
1270 } while (forward_find(lastxid, uaddr) != NULL);
1272 fi->prev = NULL;
1273 fi->next = fihead;
1274 if (fihead != NULL)
1275 fihead->prev = fi;
1276 fihead = fi;
1277 if (fitail == NULL)
1278 fitail = fi;
1280 fi->flag = 0;
1281 fi->caller_xid = caller_xid;
1283 fi->forward_xid = lastxid;
1284 fi->forward_fd = forward_fd;
1287 * Though uaddr is not allocated here, it will still be freed
1288 * from forward_destroy().
1290 fi->uaddr = uaddr;
1292 fi->reply_data = NULL;
1293 (void) cond_init(&fi->cv, USYNC_THREAD, NULL);
1295 rpcb_rmtcalls++;
1296 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
1297 assert(fitail != fi);
1298 (void) cond_signal(&fitail->cv);
1301 return (fi);
1304 static void
1305 forward_destroy(struct finfo *fi)
1307 assert(MUTEX_HELD(&finfo_lock));
1308 assert(fi->flag & FINFO_ACTIVE);
1310 if (fihead == fi) {
1311 assert(fi->prev == NULL);
1312 fihead = fi->next;
1313 } else {
1314 fi->prev->next = fi->next;
1317 if (fitail == fi) {
1318 assert(fi->next == NULL);
1319 fitail = fi->prev;
1320 } else {
1321 fi->next->prev = fi->prev;
1324 netbuffree(fi->caller_addr);
1325 free(fi->uaddr);
1326 if (fi->reply_data != NULL)
1327 t_free((char *)fi->reply_data, T_UNITDATA);
1328 (void) cond_destroy(&fi->cv);
1330 free(fi);
1332 rpcb_rmtcalls--;
1333 if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
1334 assert(fitail != NULL);
1335 (void) cond_signal(&fitail->cv);
1339 static struct finfo *
1340 forward_find(ulong_t reply_xid, char *uaddr)
1342 struct finfo *fi;
1344 assert(MUTEX_HELD(&finfo_lock));
1346 for (fi = fihead; fi != NULL; fi = fi->next) {
1347 if (fi->forward_xid == reply_xid &&
1348 strcmp(fi->uaddr, uaddr) == 0)
1349 return (fi);
1352 return (NULL);
1355 static int
1356 netbufcmp(struct netbuf *n1, struct netbuf *n2)
1358 return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1361 static struct netbuf *
1362 netbufdup(struct netbuf *ap)
1364 struct netbuf *np;
1366 np = malloc(sizeof (struct netbuf) + ap->len);
1367 if (np) {
1368 np->maxlen = np->len = ap->len;
1369 np->buf = ((char *)np) + sizeof (struct netbuf);
1370 (void) memcpy(np->buf, ap->buf, ap->len);
1372 return (np);
1375 static void
1376 netbuffree(struct netbuf *ap)
1378 free(ap);
1381 static void
1382 handle_reply(svc_input_id_t id, int fd, unsigned int events, void *cookie)
1384 struct t_unitdata *tr_data;
1385 int res;
1387 unsigned int inlen;
1388 char *buffer;
1389 XDR reply_xdrs;
1391 struct rpc_msg reply_msg;
1392 unsigned int pos;
1393 unsigned int len;
1395 struct netconfig *nconf;
1396 char *uaddr = NULL;
1398 struct finfo *fi;
1400 tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
1401 T_ADDR | T_UDATA);
1402 if (tr_data == NULL) {
1403 syslog(LOG_ERR, "handle_reply: t_alloc failed!");
1404 return;
1407 do {
1408 int moreflag = 0;
1410 if (errno == EINTR)
1411 errno = 0;
1412 res = t_rcvudata(fd, tr_data, &moreflag);
1413 if (moreflag & T_MORE) {
1414 /* Drop this packet - we have no more space. */
1415 if (debugging)
1416 fprintf(stderr, "handle_reply: recvd packet "
1417 "with T_MORE flag set\n");
1418 goto done;
1420 } while (res < 0 && t_errno == TSYSERR && errno == EINTR);
1422 if (res < 0) {
1423 if (debugging)
1424 fprintf(stderr, "handle_reply: t_rcvudata returned "
1425 "%d, t_errno %d, errno %d\n", res, t_errno, errno);
1427 if (t_errno == TLOOK)
1428 (void) t_rcvuderr(fd, NULL);
1430 goto done;
1433 inlen = tr_data->udata.len;
1434 buffer = tr_data->udata.buf;
1435 assert(buffer != NULL);
1436 xdrmem_create(&reply_xdrs, buffer, inlen, XDR_DECODE);
1438 reply_msg.acpted_rply.ar_verf = _null_auth;
1439 reply_msg.acpted_rply.ar_results.where = 0;
1440 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
1442 if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1443 xdr_destroy(&reply_xdrs);
1444 if (debugging)
1445 (void) fprintf(stderr,
1446 "handle_reply: xdr_replymsg failed\n");
1447 goto done;
1449 pos = XDR_GETPOS(&reply_xdrs);
1450 xdr_destroy(&reply_xdrs);
1452 len = inlen - pos;
1454 nconf = rpcbind_get_conf((char *)cookie);
1455 if (nconf == NULL) {
1456 syslog(LOG_ERR, "handle_reply: rpcbind_get_conf failed!");
1457 goto done;
1459 uaddr = taddr2uaddr(nconf, &tr_data->addr);
1460 if (uaddr == NULL) {
1461 syslog(LOG_ERR, "handle_reply: taddr2uaddr failed!");
1462 goto done;
1465 (void) mutex_lock(&finfo_lock);
1466 fi = forward_find(reply_msg.rm_xid, uaddr);
1467 if (fi == NULL) {
1468 (void) mutex_unlock(&finfo_lock);
1469 goto done;
1472 fi->reply_data = tr_data;
1473 tr_data = NULL;
1475 __seterr_reply(&reply_msg, &fi->reply_error);
1477 fi->res_len = len;
1478 fi->res_val = &buffer[pos];
1480 (void) cond_signal(&fi->cv);
1481 (void) mutex_unlock(&finfo_lock);
1483 done:
1484 free(uaddr);
1485 if (tr_data)
1486 t_free((char *)tr_data, T_UNITDATA);
1490 * prog: Program Number
1491 * netid: Transport Provider token
1492 * lowvp: Low version number
1493 * highvp: High version number
1495 static void
1496 find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
1498 rpcblist_ptr rbl;
1499 rpcvers_t lowv = 0;
1500 rpcvers_t highv = 0;
1502 assert(RW_LOCK_HELD(&list_rbl_lock));
1504 for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1505 if ((rbl->rpcb_map.r_prog != prog) ||
1506 (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
1507 continue;
1508 if (lowv == 0) {
1509 highv = rbl->rpcb_map.r_vers;
1510 lowv = highv;
1511 } else if (rbl->rpcb_map.r_vers < lowv) {
1512 lowv = rbl->rpcb_map.r_vers;
1513 } else if (rbl->rpcb_map.r_vers > highv) {
1514 highv = rbl->rpcb_map.r_vers;
1518 *lowvp = lowv;
1519 *highvp = highv;
1523 * returns the item with the given program, version number and netid.
1524 * If that version number is not found, it returns the item with that
1525 * program number, so that address is now returned to the caller. The
1526 * caller when makes a call to this program, version number, the call
1527 * will fail and it will return with PROGVERS_MISMATCH. The user can
1528 * then determine the highest and the lowest version number for this
1529 * program using clnt_geterr() and use those program version numbers.
1531 * Returns the RPCBLIST for the given prog, vers and netid
1533 * prog: Program Number
1534 * vers: Version Number
1535 * netid: Transport Provider token
1537 static rpcblist_ptr
1538 find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
1540 rpcblist_ptr hit = NULL;
1541 rpcblist_ptr rbl;
1543 assert(RW_LOCK_HELD(&list_rbl_lock));
1545 for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1546 if ((rbl->rpcb_map.r_prog != prog) ||
1547 (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
1548 continue;
1549 hit = rbl;
1550 if (rbl->rpcb_map.r_vers == vers)
1551 break;
1554 return (hit);
1558 * If the caller is from our zone and we know
1559 * who it is, we return the uid.
1561 uid_t
1562 rpcb_caller_uid(SVCXPRT *transp)
1564 ucred_t *uc = alloca(ucred_size());
1566 if (svc_getcallerucred(transp, &uc) != 0 ||
1567 (ucred_getzoneid(uc)) != myzone) {
1568 return (-1);
1569 } else {
1570 return (ucred_geteuid(uc));
1575 * Copies the name associated with the uid of the caller and returns
1576 * a pointer to it. Similar to getwd().
1578 char *
1579 getowner(SVCXPRT *transp, char *owner)
1581 uid_t uid = rpcb_caller_uid(transp);
1583 switch (uid) {
1584 case -1:
1585 return (strcpy(owner, "unknown"));
1586 case 0:
1587 return (strcpy(owner, "superuser"));
1588 default:
1589 (void) sprintf(owner, "%u", uid);
1590 return (owner);
1594 #ifdef PORTMAP
1596 * Add this to the pmap list only if it is UDP or TCP.
1598 static int
1599 add_pmaplist(RPCB *arg)
1601 pmap pmap;
1602 pmaplist *pml;
1603 int h1, h2, h3, h4, p1, p2;
1605 if (strcmp(arg->r_netid, udptrans) == 0) {
1606 /* It is UDP! */
1607 pmap.pm_prot = IPPROTO_UDP;
1608 } else if (strcmp(arg->r_netid, tcptrans) == 0) {
1609 /* It is TCP */
1610 pmap.pm_prot = IPPROTO_TCP;
1611 } else
1612 /* Not a IP protocol */
1613 return (0);
1615 /* interpret the universal address for TCP/IP */
1616 if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1617 &h1, &h2, &h3, &h4, &p1, &p2) != 6)
1618 return (0);
1619 pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1620 pmap.pm_prog = arg->r_prog;
1621 pmap.pm_vers = arg->r_vers;
1623 * add to END of list
1625 pml = (pmaplist *) malloc((uint_t)sizeof (pmaplist));
1626 if (pml == NULL) {
1627 (void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1628 return (1);
1630 pml->pml_map = pmap;
1631 pml->pml_next = NULL;
1633 (void) rw_wrlock(&list_pml_lock);
1634 if (list_pml == NULL) {
1635 list_pml = pml;
1636 } else {
1637 pmaplist *fnd;
1639 /* Attach to the end of the list */
1640 for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1642 fnd->pml_next = pml;
1644 (void) rw_unlock(&list_pml_lock);
1646 return (0);
1650 * Delete this from the pmap list only if it is UDP or TCP.
1653 del_pmaplist(RPCB *arg)
1655 pmaplist *pml;
1656 pmaplist *prevpml, *fnd;
1657 rpcport_t prot;
1659 if (strcmp(arg->r_netid, udptrans) == 0) {
1660 /* It is UDP! */
1661 prot = IPPROTO_UDP;
1662 } else if (strcmp(arg->r_netid, tcptrans) == 0) {
1663 /* It is TCP */
1664 prot = IPPROTO_TCP;
1665 } else if (arg->r_netid[0] == '\0') {
1666 prot = 0; /* Remove all occurrences */
1667 } else {
1668 /* Not a IP protocol */
1669 return (0);
1672 assert(RW_WRITE_HELD(&list_pml_lock));
1674 for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1675 if ((pml->pml_map.pm_prog != arg->r_prog) ||
1676 (pml->pml_map.pm_vers != arg->r_vers) ||
1677 (prot && (pml->pml_map.pm_prot != prot))) {
1678 /* both pml & prevpml move forwards */
1679 prevpml = pml;
1680 pml = pml->pml_next;
1681 continue;
1683 /* found it; pml moves forward, prevpml stays */
1684 fnd = pml;
1685 pml = pml->pml_next;
1686 if (prevpml == NULL)
1687 list_pml = pml;
1688 else
1689 prevpml->pml_next = pml;
1690 free(fnd);
1693 return (0);
1695 #endif /* PORTMAP */