dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rpcbind / pmap_svc.c
blobb5b3100e3c17b44f09841ddefad561ae419e65f1
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
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 * pmap_svc.c
43 * The server procedure for the version 2 portmaper.
44 * All the portmapper related interface from the portmap side.
47 #include <rpc/rpc.h>
48 #include <tcpd.h>
50 #include "rpcbind.h"
52 #ifdef PORTMAP
53 #include <stdio.h>
54 #include <alloca.h>
55 #include <ucred.h>
56 #include <rpc/pmap_prot.h>
57 #include <rpc/rpcb_prot.h>
58 #include <assert.h>
60 static bool_t pmapproc_change(struct svc_req *, SVCXPRT *, unsigned long);
61 static bool_t pmapproc_getport(struct svc_req *, SVCXPRT *);
62 static bool_t pmapproc_dump(struct svc_req *, SVCXPRT *);
65 * Called for all the version 2 inquiries.
67 void
68 pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
70 rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
72 switch (rqstp->rq_proc) {
73 case PMAPPROC_NULL:
75 * Null proc call
77 PMAP_CHECK(xprt, rqstp->rq_proc);
79 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_void, NULL)) &&
80 debugging) {
81 if (doabort) {
82 rpcbind_abort();
85 break;
87 case PMAPPROC_SET:
89 * Set a program, version to port mapping
91 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
92 break;
94 case PMAPPROC_UNSET:
96 * Remove a program, version to port mapping.
98 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
99 break;
101 case PMAPPROC_GETPORT:
103 * Lookup the mapping for a program, version and return its
104 * port number.
106 pmapproc_getport(rqstp, xprt);
107 break;
109 case PMAPPROC_DUMP:
111 * Return the current set of mapped program, version
113 PMAP_CHECK(xprt, rqstp->rq_proc);
114 pmapproc_dump(rqstp, xprt);
115 break;
117 case PMAPPROC_CALLIT:
119 * Calls a procedure on the local machine. If the requested
120 * procedure is not registered this procedure does not return
121 * error information!!
122 * This procedure is only supported on rpc/udp and calls via
123 * rpc/udp. It passes null authentication parameters.
125 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
126 break;
128 default:
129 PMAP_CHECK(xprt, rqstp->rq_proc);
130 svcerr_noproc(xprt);
131 break;
136 * returns the item with the given program, version number. If that version
137 * number is not found, it returns the item with that program number, so that
138 * the port number is now returned to the caller. The caller when makes a
139 * call to this program, version number, the call will fail and it will
140 * return with PROGVERS_MISMATCH. The user can then determine the highest
141 * and the lowest version number for this program using clnt_geterr() and
142 * use those program version numbers.
144 static PMAPLIST *
145 find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
147 PMAPLIST *hit = NULL;
148 PMAPLIST *pml;
150 assert(RW_LOCK_HELD(&list_pml_lock));
152 for (pml = list_pml; pml != NULL; pml = pml->pml_next) {
153 if ((pml->pml_map.pm_prog != prog) ||
154 (pml->pml_map.pm_prot != prot))
155 continue;
156 hit = pml;
157 if (pml->pml_map.pm_vers == vers)
158 break;
161 return (hit);
164 /* ARGSUSED */
165 static bool_t
166 pmapproc_change(struct svc_req *rqstp, SVCXPRT *xprt, unsigned long op)
168 PMAP reg;
169 RPCB rpcbreg;
170 int ans;
171 struct sockaddr_in *who;
172 char owner[64];
174 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)&reg)) {
175 svcerr_decode(xprt);
176 return (FALSE);
178 who = (struct sockaddr_in *)svc_getrpccaller(xprt)->buf;
180 /* Don't allow unset/set from remote. */
181 if (!localxprt(xprt, B_TRUE)) {
182 ans = FALSE;
183 goto done_change;
186 rpcbreg.r_owner = getowner(xprt, owner);
188 if ((op == PMAPPROC_SET) && (reg.pm_port < IPPORT_RESERVED) &&
189 (ntohs(who->sin_port) >= IPPORT_RESERVED)) {
190 ans = FALSE;
191 goto done_change;
193 rpcbreg.r_prog = reg.pm_prog;
194 rpcbreg.r_vers = reg.pm_vers;
196 if (op == PMAPPROC_SET) {
197 char buf[32];
199 sprintf(buf, "0.0.0.0.%d.%d", (reg.pm_port >> 8) & 0xff,
200 reg.pm_port & 0xff);
201 rpcbreg.r_addr = buf;
202 if (reg.pm_prot == IPPROTO_UDP) {
203 rpcbreg.r_netid = udptrans;
204 } else if (reg.pm_prot == IPPROTO_TCP) {
205 rpcbreg.r_netid = tcptrans;
206 } else {
207 ans = FALSE;
208 goto done_change;
210 ans = map_set(&rpcbreg, rpcbreg.r_owner);
211 } else if (op == PMAPPROC_UNSET) {
212 bool_t ans1, ans2;
214 rpcbreg.r_addr = NULL;
215 rpcbreg.r_netid = tcptrans;
216 ans1 = map_unset(&rpcbreg, rpcbreg.r_owner);
217 rpcbreg.r_netid = udptrans;
218 ans2 = map_unset(&rpcbreg, rpcbreg.r_owner);
219 ans = ans1 || ans2;
220 } else {
221 ans = FALSE;
223 done_change:
224 PMAP_LOG(ans, xprt, op, reg.pm_prog);
226 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_long, (caddr_t)&ans)) &&
227 debugging) {
228 fprintf(stderr, "portmap: svc_sendreply\n");
229 if (doabort) {
230 rpcbind_abort();
233 if (op == PMAPPROC_SET)
234 rpcbs_set(RPCBVERS_2_STAT, ans);
235 else
236 rpcbs_unset(RPCBVERS_2_STAT, ans);
237 return (TRUE);
240 /* ARGSUSED */
241 static bool_t
242 pmapproc_getport(struct svc_req *rqstp, SVCXPRT *xprt)
244 PMAP reg;
245 int port = 0;
246 PMAPLIST *fnd;
247 bool_t rbl_locked = FALSE;
249 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)&reg)) {
250 svcerr_decode(xprt);
251 return (FALSE);
253 PMAP_CHECK_RET(xprt, rqstp->rq_proc, FALSE);
255 (void) rw_rdlock(&list_pml_lock);
256 retry:
257 fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot);
258 if (fnd) {
259 char serveuaddr[32], *ua;
260 int h1, h2, h3, h4, p1, p2;
261 char *netid;
263 if (reg.pm_prot == IPPROTO_UDP) {
264 ua = udp_uaddr;
265 netid = udptrans;
266 } else {
267 ua = tcp_uaddr; /* To get the len */
268 netid = tcptrans;
270 if (ua == NULL) {
271 (void) rw_unlock(&list_pml_lock);
272 if (rbl_locked)
273 (void) rw_unlock(&list_rbl_lock);
274 goto sendreply;
276 if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3,
277 &h4, &p1, &p2) == 6) {
278 p1 = (fnd->pml_map.pm_port >> 8) & 0xff;
279 p2 = (fnd->pml_map.pm_port) & 0xff;
280 sprintf(serveuaddr, "%d.%d.%d.%d.%d.%d",
281 h1, h2, h3, h4, p1, p2);
282 if (is_bound(netid, serveuaddr)) {
283 port = fnd->pml_map.pm_port;
284 } else { /* this service is dead; delete it */
285 if (!rbl_locked) {
286 (void) rw_unlock(&list_pml_lock);
287 (void) rw_wrlock(&list_rbl_lock);
288 (void) rw_wrlock(&list_pml_lock);
289 rbl_locked = TRUE;
290 goto retry;
292 delete_prog(reg.pm_prog);
296 (void) rw_unlock(&list_pml_lock);
297 if (rbl_locked)
298 (void) rw_unlock(&list_rbl_lock);
300 sendreply:
301 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_long, (caddr_t)&port)) &&
302 debugging) {
303 (void) fprintf(stderr, "portmap: svc_sendreply\n");
304 if (doabort) {
305 rpcbind_abort();
308 rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
309 reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
310 port ? udptrans : "");
312 return (TRUE);
315 /* ARGSUSED */
316 static bool_t
317 pmapproc_dump(struct svc_req *rqstp, SVCXPRT *xprt)
319 if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
320 svcerr_decode(xprt);
321 return (FALSE);
324 (void) rw_rdlock(&list_pml_lock);
325 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_pmaplist_ptr,
326 (caddr_t)&list_pml)) && debugging) {
327 (void) rw_unlock(&list_pml_lock);
328 (void) fprintf(stderr, "portmap: svc_sendreply\n");
329 if (doabort) {
330 rpcbind_abort();
332 } else {
333 (void) rw_unlock(&list_pml_lock);
336 return (TRUE);
338 #endif /* PORTMAP */
341 * Is the transport local? The original rpcbind code tried to
342 * figure out all the network interfaces but there can be a nearly
343 * infinite number of network interfaces. And the number of interfaces can
344 * vary over time.
346 * Note that when we get here, we've already establised that we're
347 * dealing with a TCP/IP endpoint.
349 boolean_t
350 localxprt(SVCXPRT *transp, boolean_t forceipv4)
352 struct sockaddr_gen *sgen = svc_getgencaller(transp);
354 switch (SGFAM(sgen)) {
355 case AF_INET:
356 break;
357 case AF_INET6:
358 if (forceipv4)
359 return (B_FALSE);
360 break;
361 default:
362 return (B_FALSE);
366 * Get the peer's uid; if it is known it is sufficiently
367 * authenticated and considered local. The magic behind this
368 * call is all in libnsl.
370 return (rpcb_caller_uid(transp) != -1);