1 /*
2 * CDDL HEADER START
3 *
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.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /*
27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 */
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31 /*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41 /*
42 * pmap_svc.c
43 * The server procedure for the version 2 portmaper.
44 * All the portmapper related interface from the portmap side.
45 */
46
47 #include <rpc/rpc.h>
48 #include <tcpd.h>
49
50 #include "rpcbind.h"
51
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>
59
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 *);
63
64 /*
65 * Called for all the version 2 inquiries.
66 */
67 void
pmap_service(struct svc_req * rqstp,SVCXPRT * xprt)68 pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
69 {
70 rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
71
72 switch (rqstp->rq_proc) {
73 case PMAPPROC_NULL:
74 /*
75 * Null proc call
76 */
77 PMAP_CHECK(xprt, rqstp->rq_proc);
78
79 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_void, NULL)) &&
80 debugging) {
81 if (doabort) {
82 rpcbind_abort();
83 }
84 }
85 break;
86
87 case PMAPPROC_SET:
88 /*
89 * Set a program, version to port mapping
90 */
91 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
92 break;
93
94 case PMAPPROC_UNSET:
95 /*
96 * Remove a program, version to port mapping.
97 */
98 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
99 break;
100
101 case PMAPPROC_GETPORT:
102 /*
103 * Lookup the mapping for a program, version and return its
104 * port number.
105 */
106 pmapproc_getport(rqstp, xprt);
107 break;
108
109 case PMAPPROC_DUMP:
110 /*
111 * Return the current set of mapped program, version
112 */
113 PMAP_CHECK(xprt, rqstp->rq_proc);
114 pmapproc_dump(rqstp, xprt);
115 break;
116
117 case PMAPPROC_CALLIT:
118 /*
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.
124 */
125 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
126 break;
127
128 default:
129 PMAP_CHECK(xprt, rqstp->rq_proc);
130 svcerr_noproc(xprt);
131 break;
132 }
133 }
134
135 /*
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.
143 */
144 static PMAPLIST *
find_service_pmap(rpcprog_t prog,rpcvers_t vers,rpcprot_t prot)145 find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
146 {
147 PMAPLIST *hit = NULL;
148 PMAPLIST *pml;
149
150 assert(RW_LOCK_HELD(&list_pml_lock));
151
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;
159 }
160
161 return (hit);
162 }
163
164 /* ARGSUSED */
165 static bool_t
pmapproc_change(struct svc_req * rqstp,SVCXPRT * xprt,unsigned long op)166 pmapproc_change(struct svc_req *rqstp, SVCXPRT *xprt, unsigned long op)
167 {
168 PMAP reg;
169 RPCB rpcbreg;
170 int ans;
171 struct sockaddr_in *who;
172 char owner[64];
173
174 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)®)) {
175 svcerr_decode(xprt);
176 return (FALSE);
177 }
178 who = (struct sockaddr_in *)svc_getrpccaller(xprt)->buf;
179
180 /* Don't allow unset/set from remote. */
181 if (!localxprt(xprt, B_TRUE)) {
182 ans = FALSE;
183 goto done_change;
184 }
185
186 rpcbreg.r_owner = getowner(xprt, owner);
187
188 if ((op == PMAPPROC_SET) && (reg.pm_port < IPPORT_RESERVED) &&
189 (ntohs(who->sin_port) >= IPPORT_RESERVED)) {
190 ans = FALSE;
191 goto done_change;
192 }
193 rpcbreg.r_prog = reg.pm_prog;
194 rpcbreg.r_vers = reg.pm_vers;
195
196 if (op == PMAPPROC_SET) {
197 char buf[32];
198
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;
209 }
210 ans = map_set(&rpcbreg, rpcbreg.r_owner);
211 } else if (op == PMAPPROC_UNSET) {
212 bool_t ans1, ans2;
213
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;
222 }
223 done_change:
224 PMAP_LOG(ans, xprt, op, reg.pm_prog);
225
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();
231 }
232 }
233 if (op == PMAPPROC_SET)
234 rpcbs_set(RPCBVERS_2_STAT, ans);
235 else
236 rpcbs_unset(RPCBVERS_2_STAT, ans);
237 return (TRUE);
238 }
239
240 /* ARGSUSED */
241 static bool_t
pmapproc_getport(struct svc_req * rqstp,SVCXPRT * xprt)242 pmapproc_getport(struct svc_req *rqstp, SVCXPRT *xprt)
243 {
244 PMAP reg;
245 int port = 0;
246 PMAPLIST *fnd;
247 bool_t rbl_locked = FALSE;
248
249 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)®)) {
250 svcerr_decode(xprt);
251 return (FALSE);
252 }
253 PMAP_CHECK_RET(xprt, rqstp->rq_proc, FALSE);
254
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;
262
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;
269 }
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;
275 }
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;
291 }
292 delete_prog(reg.pm_prog);
293 }
294 }
295 }
296 (void) rw_unlock(&list_pml_lock);
297 if (rbl_locked)
298 (void) rw_unlock(&list_rbl_lock);
299
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();
306 }
307 }
308 rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
309 reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
310 port ? udptrans : "");
311
312 return (TRUE);
313 }
314
315 /* ARGSUSED */
316 static bool_t
pmapproc_dump(struct svc_req * rqstp,SVCXPRT * xprt)317 pmapproc_dump(struct svc_req *rqstp, SVCXPRT *xprt)
318 {
319 if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
320 svcerr_decode(xprt);
321 return (FALSE);
322 }
323
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();
331 }
332 } else {
333 (void) rw_unlock(&list_pml_lock);
334 }
335
336 return (TRUE);
337 }
338 #endif /* PORTMAP */
339
340 /*
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.
345 *
346 * Note that when we get here, we've already establised that we're
347 * dealing with a TCP/IP endpoint.
348 */
349 boolean_t
localxprt(SVCXPRT * transp,boolean_t forceipv4)350 localxprt(SVCXPRT *transp, boolean_t forceipv4)
351 {
352 struct sockaddr_gen *sgen = svc_getgencaller(transp);
353
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);
363 }
364
365 /*
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.
369 */
370 return (rpcb_caller_uid(transp) != -1);
371 }
372