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 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 * 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 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 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 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 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