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 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29 * University Copyright- Copyright (c) 1982, 1986, 1988
30 * The Regents of the University of California
31 * All Rights Reserved
32 *
33 * University Acknowledgment- Portions of this document are derived from
34 * software developed by the University of California, Berkeley, and its
35 * contributors.
36 */
37
38 #pragma ident "%Z%%M% %I% %E% SMI"
39
40 /*
41 * pmap_svc.c
42 * The server procedure for the version 2 portmaper.
43 * All the portmapper related interface from the portmap side.
44 */
45
46 #ifdef PORTMAP
47 #include <stdio.h>
48 #include <alloca.h>
49 #include <ucred.h>
50 #include <rpc/rpc.h>
51 #include <rpc/pmap_prot.h>
52 #include <rpc/rpcb_prot.h>
53 #include "rpcbind.h"
54
55 #ifdef RPCBIND_DEBUG
56 #include <netdir.h>
57 #endif
58
59 static PMAPLIST *find_service_pmap();
60 static bool_t pmapproc_change();
61 static bool_t pmapproc_getport();
62 static bool_t pmapproc_dump();
63
64 /*
65 * Called for all the version 2 inquiries.
66 */
67 void
pmap_service(rqstp,xprt)68 pmap_service(rqstp, xprt)
69 register struct svc_req *rqstp;
70 register SVCXPRT *xprt;
71 {
72 rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
73 switch (rqstp->rq_proc) {
74 case PMAPPROC_NULL:
75 /*
76 * Null proc call
77 */
78 #ifdef RPCBIND_DEBUG
79 fprintf(stderr, "PMAPPROC_NULL\n");
80 #endif
81 PMAP_CHECK(xprt, rqstp->rq_proc);
82
83 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_void, NULL)) &&
84 debugging) {
85 if (doabort) {
86 rpcbind_abort();
87 }
88 }
89 break;
90
91 case PMAPPROC_SET:
92 /*
93 * Set a program, version to port mapping
94 */
95 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
96 break;
97
98 case PMAPPROC_UNSET:
99 /*
100 * Remove a program, version to port mapping.
101 */
102 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
103 break;
104
105 case PMAPPROC_GETPORT:
106 /*
107 * Lookup the mapping for a program, version and return its
108 * port number.
109 */
110 pmapproc_getport(rqstp, xprt);
111 break;
112
113 case PMAPPROC_DUMP:
114 /*
115 * Return the current set of mapped program, version
116 */
117 #ifdef RPCBIND_DEBUG
118 fprintf(stderr, "PMAPPROC_DUMP\n");
119 #endif
120 PMAP_CHECK(xprt, rqstp->rq_proc);
121 pmapproc_dump(rqstp, xprt);
122 break;
123
124 case PMAPPROC_CALLIT:
125 /*
126 * Calls a procedure on the local machine. If the requested
127 * procedure is not registered this procedure does not return
128 * error information!!
129 * This procedure is only supported on rpc/udp and calls via
130 * rpc/udp. It passes null authentication parameters.
131 */
132 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
133 break;
134
135 default:
136 PMAP_CHECK(xprt, rqstp->rq_proc);
137 svcerr_noproc(xprt);
138 break;
139 }
140 }
141
142 /*
143 * returns the item with the given program, version number. If that version
144 * number is not found, it returns the item with that program number, so that
145 * the port number is now returned to the caller. The caller when makes a
146 * call to this program, version number, the call will fail and it will
147 * return with PROGVERS_MISMATCH. The user can then determine the highest
148 * and the lowest version number for this program using clnt_geterr() and
149 * use those program version numbers.
150 */
151 static PMAPLIST *
find_service_pmap(prog,vers,prot)152 find_service_pmap(prog, vers, prot)
153 ulong_t prog;
154 ulong_t vers;
155 ulong_t prot;
156 {
157 register PMAPLIST *hit = NULL;
158 register PMAPLIST *pml;
159
160 for (pml = list_pml; pml != NULL; pml = pml->pml_next) {
161 if ((pml->pml_map.pm_prog != prog) ||
162 (pml->pml_map.pm_prot != prot))
163 continue;
164 hit = pml;
165 if (pml->pml_map.pm_vers == vers)
166 break;
167 }
168 return (hit);
169 }
170
171 extern char *getowner(SVCXPRT *xprt, char *);
172
173 /*ARGSUSED*/
174 static bool_t
pmapproc_change(rqstp,xprt,op)175 pmapproc_change(rqstp, xprt, op)
176 struct svc_req *rqstp;
177 register SVCXPRT *xprt;
178 unsigned long op;
179 {
180 PMAP reg;
181 RPCB rpcbreg;
182 int ans;
183 struct sockaddr_in *who;
184 extern bool_t map_set(), map_unset();
185 char owner[64];
186
187 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)®)) {
188 svcerr_decode(xprt);
189 return (FALSE);
190 }
191 who = svc_getcaller(xprt);
192
193 #ifdef RPCBIND_DEBUG
194 fprintf(stderr, "%s request for (%lu, %lu) : ",
195 op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET",
196 reg.pm_prog, reg.pm_vers);
197 #endif
198
199 /* Don't allow unset/set from remote. */
200 if (!localxprt(xprt, B_TRUE)) {
201 ans = FALSE;
202 goto done_change;
203 }
204
205 rpcbreg.r_owner = getowner(xprt, owner);
206
207 if ((op == PMAPPROC_SET) && (reg.pm_port < IPPORT_RESERVED) &&
208 (ntohs(who->sin_port) >= IPPORT_RESERVED)) {
209 ans = FALSE;
210 goto done_change;
211 }
212 rpcbreg.r_prog = reg.pm_prog;
213 rpcbreg.r_vers = reg.pm_vers;
214
215 if (op == PMAPPROC_SET) {
216 char buf[32];
217
218 sprintf(buf, "0.0.0.0.%d.%d", (reg.pm_port >> 8) & 0xff,
219 reg.pm_port & 0xff);
220 rpcbreg.r_addr = buf;
221 if (reg.pm_prot == IPPROTO_UDP) {
222 rpcbreg.r_netid = udptrans;
223 } else if (reg.pm_prot == IPPROTO_TCP) {
224 rpcbreg.r_netid = tcptrans;
225 } else {
226 ans = FALSE;
227 goto done_change;
228 }
229 ans = map_set(&rpcbreg, rpcbreg.r_owner);
230 } else if (op == PMAPPROC_UNSET) {
231 bool_t ans1, ans2;
232
233 rpcbreg.r_addr = NULL;
234 rpcbreg.r_netid = tcptrans;
235 ans1 = map_unset(&rpcbreg, rpcbreg.r_owner);
236 rpcbreg.r_netid = udptrans;
237 ans2 = map_unset(&rpcbreg, rpcbreg.r_owner);
238 ans = ans1 || ans2;
239 } else {
240 ans = FALSE;
241 }
242 done_change:
243 PMAP_LOG(ans, xprt, op, reg.pm_prog);
244
245 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_long, (caddr_t)&ans)) &&
246 debugging) {
247 fprintf(stderr, "portmap: svc_sendreply\n");
248 if (doabort) {
249 rpcbind_abort();
250 }
251 }
252 #ifdef RPCBIND_DEBUG
253 fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
254 #endif
255 if (op == PMAPPROC_SET)
256 rpcbs_set(RPCBVERS_2_STAT, ans);
257 else
258 rpcbs_unset(RPCBVERS_2_STAT, ans);
259 return (TRUE);
260 }
261
262 /* ARGSUSED */
263 static bool_t
pmapproc_getport(rqstp,xprt)264 pmapproc_getport(rqstp, xprt)
265 struct svc_req *rqstp;
266 register SVCXPRT *xprt;
267 {
268 PMAP reg;
269 int port = 0;
270 PMAPLIST *fnd;
271 #ifdef RPCBIND_DEBUG
272 char *uaddr;
273 #endif
274
275 if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)®)) {
276 svcerr_decode(xprt);
277 return (FALSE);
278 }
279 PMAP_CHECK_RET(xprt, rqstp->rq_proc, FALSE);
280
281 #ifdef RPCBIND_DEBUG
282 uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid),
283 svc_getrpccaller(xprt));
284 fprintf(stderr, "PMAP_GETPORT request for (%lu, %lu, %s) from %s :",
285 reg.pm_prog, reg.pm_vers,
286 reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr);
287 free(uaddr);
288 #endif
289 fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot);
290 if (fnd) {
291 char serveuaddr[32], *ua;
292 int h1, h2, h3, h4, p1, p2;
293 char *netid;
294
295 if (reg.pm_prot == IPPROTO_UDP) {
296 ua = udp_uaddr;
297 netid = udptrans;
298 } else {
299 ua = tcp_uaddr; /* To get the len */
300 netid = tcptrans;
301 }
302 if (ua == NULL) {
303 goto sendreply;
304 }
305 if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3,
306 &h4, &p1, &p2) == 6) {
307 p1 = (fnd->pml_map.pm_port >> 8) & 0xff;
308 p2 = (fnd->pml_map.pm_port) & 0xff;
309 sprintf(serveuaddr, "%d.%d.%d.%d.%d.%d",
310 h1, h2, h3, h4, p1, p2);
311 if (is_bound(netid, serveuaddr)) {
312 port = fnd->pml_map.pm_port;
313 } else { /* this service is dead; delete it */
314 delete_prog(reg.pm_prog);
315 }
316 }
317 }
318 sendreply:
319 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_long, (caddr_t)&port)) &&
320 debugging) {
321 (void) fprintf(stderr, "portmap: svc_sendreply\n");
322 if (doabort) {
323 rpcbind_abort();
324 }
325 }
326 #ifdef RPCBIND_DEBUG
327 fprintf(stderr, "port = %d\n", port);
328 #endif
329 rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
330 reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
331 port ? udptrans : "");
332
333 return (TRUE);
334 }
335
336 /* ARGSUSED */
337 static bool_t
pmapproc_dump(rqstp,xprt)338 pmapproc_dump(rqstp, xprt)
339 struct svc_req *rqstp;
340 register SVCXPRT *xprt;
341 {
342 if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
343 svcerr_decode(xprt);
344 return (FALSE);
345 }
346 if ((!svc_sendreply(xprt, (xdrproc_t)xdr_pmaplist_ptr,
347 (caddr_t)&list_pml)) && debugging) {
348 (void) fprintf(stderr, "portmap: svc_sendreply\n");
349 if (doabort) {
350 rpcbind_abort();
351 }
352 }
353 return (TRUE);
354 }
355
356 /*
357 * Is the transport local? The original rpcbind code tried to
358 * figure out all the network interfaces but there can be a nearly
359 * infinite number of network interfaces. And the number of interfaces can
360 * vary over time.
361 *
362 * Note that when we get here, we've already establised that we're
363 * dealing with a TCP/IP endpoint.
364 */
365 boolean_t
localxprt(SVCXPRT * transp,boolean_t forceipv4)366 localxprt(SVCXPRT *transp, boolean_t forceipv4)
367 {
368 struct sockaddr_gen *sgen = svc_getgencaller(transp);
369
370 switch (SGFAM(sgen)) {
371 case AF_INET:
372 break;
373 case AF_INET6:
374 if (forceipv4)
375 return (B_FALSE);
376 break;
377 default:
378 return (B_FALSE);
379 }
380
381 /*
382 * Get the peer's uid; if it is known it is sufficiently
383 * authenticated and considered local. The magic behind this
384 * call is all in libnsl.
385 */
386 return (rpcb_caller_uid(transp) != -1);
387 }
388 #endif /* PORTMAP */
389