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