1 /* $NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $ */ 2 /* $FreeBSD$ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (c) 2009, Sun Microsystems, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * - Neither the name of Sun Microsystems, Inc. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /* 34 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. 35 */ 36 37 /* #ident "@(#)pmap_svc.c 1.14 93/07/05 SMI" */ 38 39 #if 0 40 #ifndef lint 41 static char sccsid[] = "@(#)pmap_svc.c 1.23 89/04/05 Copyr 1984 Sun Micro"; 42 #endif 43 #endif 44 45 /* 46 * pmap_svc.c 47 * The server procedure for the version 2 portmaper. 48 * All the portmapper related interface from the portmap side. 49 */ 50 51 #ifdef PORTMAP 52 #include <sys/types.h> 53 #include <sys/socket.h> 54 #include <stdio.h> 55 #include <rpc/rpc.h> 56 #include <rpc/pmap_prot.h> 57 #include <rpc/rpcb_prot.h> 58 #ifdef RPCBIND_DEBUG 59 #include <stdlib.h> 60 #endif 61 #include "rpcbind.h" 62 63 static struct pmaplist *find_service_pmap(rpcprog_t, rpcvers_t, 64 rpcprot_t); 65 static bool_t pmapproc_change(struct svc_req *, SVCXPRT *, u_long); 66 static bool_t pmapproc_getport(struct svc_req *, SVCXPRT *); 67 static bool_t pmapproc_dump(struct svc_req *, SVCXPRT *); 68 69 /* 70 * Called for all the version 2 inquiries. 71 */ 72 void 73 pmap_service(struct svc_req *rqstp, SVCXPRT *xprt) 74 { 75 rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc); 76 switch (rqstp->rq_proc) { 77 case PMAPPROC_NULL: 78 /* 79 * Null proc call 80 */ 81 #ifdef RPCBIND_DEBUG 82 if (debugging) 83 fprintf(stderr, "PMAPPROC_NULL\n"); 84 #endif 85 check_access(xprt, rqstp->rq_proc, NULL, PMAPVERS); 86 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) && 87 debugging) { 88 if (doabort) { 89 rpcbind_abort(); 90 } 91 } 92 break; 93 94 case PMAPPROC_SET: 95 /* 96 * Set a program, version to port mapping 97 */ 98 pmapproc_change(rqstp, xprt, rqstp->rq_proc); 99 break; 100 101 case PMAPPROC_UNSET: 102 /* 103 * Remove a program, version to port mapping. 104 */ 105 pmapproc_change(rqstp, xprt, rqstp->rq_proc); 106 break; 107 108 case PMAPPROC_GETPORT: 109 /* 110 * Lookup the mapping for a program, version and return its 111 * port number. 112 */ 113 pmapproc_getport(rqstp, xprt); 114 break; 115 116 case PMAPPROC_DUMP: 117 /* 118 * Return the current set of mapped program, version 119 */ 120 #ifdef RPCBIND_DEBUG 121 if (debugging) 122 fprintf(stderr, "PMAPPROC_DUMP\n"); 123 #endif 124 pmapproc_dump(rqstp, xprt); 125 break; 126 127 case PMAPPROC_CALLIT: 128 /* 129 * Calls a procedure on the local machine. If the requested 130 * procedure is not registered this procedure does not return 131 * error information!! 132 * This procedure is only supported on rpc/udp and calls via 133 * rpc/udp. It passes null authentication parameters. 134 */ 135 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS); 136 break; 137 138 default: 139 svcerr_noproc(xprt); 140 break; 141 } 142 } 143 144 /* 145 * returns the item with the given program, version number. If that version 146 * number is not found, it returns the item with that program number, so that 147 * the port number is now returned to the caller. The caller when makes a 148 * call to this program, version number, the call will fail and it will 149 * return with PROGVERS_MISMATCH. The user can then determine the highest 150 * and the lowest version number for this program using clnt_geterr() and 151 * use those program version numbers. 152 */ 153 static struct pmaplist * 154 find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot) 155 { 156 register struct pmaplist *hit = NULL; 157 register struct pmaplist *pml; 158 159 for (pml = list_pml; pml != NULL; pml = pml->pml_next) { 160 if ((pml->pml_map.pm_prog != prog) || 161 (pml->pml_map.pm_prot != prot)) 162 continue; 163 hit = pml; 164 if (pml->pml_map.pm_vers == vers) 165 break; 166 } 167 return (hit); 168 } 169 170 static bool_t 171 pmapproc_change(struct svc_req *rqstp __unused, SVCXPRT *xprt, unsigned long op) 172 { 173 struct pmap reg; 174 RPCB rpcbreg; 175 long ans; 176 struct sockaddr_in *who; 177 uid_t uid; 178 char uidbuf[32]; 179 180 #ifdef RPCBIND_DEBUG 181 if (debugging) 182 fprintf(stderr, "%s request for (%lu, %lu) : ", 183 op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET", 184 reg.pm_prog, reg.pm_vers); 185 #endif 186 187 if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)®)) { 188 svcerr_decode(xprt); 189 return (FALSE); 190 } 191 192 if (!check_access(xprt, op, ®, PMAPVERS)) { 193 svcerr_weakauth(xprt); 194 return FALSE; 195 } 196 197 who = svc_getcaller(xprt); 198 199 /* 200 * Can't use getpwnam here. We might end up calling ourselves 201 * and looping. 202 */ 203 if (__rpc_get_local_uid(xprt, &uid) < 0) 204 rpcbreg.r_owner = "unknown"; 205 else if (uid == 0) 206 rpcbreg.r_owner = "superuser"; 207 else { 208 /* r_owner will be strdup-ed later */ 209 snprintf(uidbuf, sizeof uidbuf, "%d", uid); 210 rpcbreg.r_owner = uidbuf; 211 } 212 213 rpcbreg.r_prog = reg.pm_prog; 214 rpcbreg.r_vers = reg.pm_vers; 215 216 if (op == PMAPPROC_SET) { 217 char buf[32]; 218 219 snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", 220 (int)((reg.pm_port >> 8) & 0xff), 221 (int)(reg.pm_port & 0xff)); 222 rpcbreg.r_addr = buf; 223 if (reg.pm_prot == IPPROTO_UDP) { 224 rpcbreg.r_netid = udptrans; 225 } else if (reg.pm_prot == IPPROTO_TCP) { 226 rpcbreg.r_netid = tcptrans; 227 } else { 228 ans = FALSE; 229 goto done_change; 230 } 231 ans = map_set(&rpcbreg, rpcbreg.r_owner); 232 } else if (op == PMAPPROC_UNSET) { 233 bool_t ans1, ans2; 234 235 rpcbreg.r_addr = NULL; 236 rpcbreg.r_netid = tcptrans; 237 ans1 = map_unset(&rpcbreg, rpcbreg.r_owner); 238 rpcbreg.r_netid = udptrans; 239 ans2 = map_unset(&rpcbreg, rpcbreg.r_owner); 240 ans = ans1 || ans2; 241 } else { 242 ans = FALSE; 243 } 244 done_change: 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 if (debugging) 254 fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed"); 255 #endif 256 if (op == PMAPPROC_SET) 257 rpcbs_set(RPCBVERS_2_STAT, ans); 258 else 259 rpcbs_unset(RPCBVERS_2_STAT, ans); 260 return (TRUE); 261 } 262 263 /* ARGSUSED */ 264 static bool_t 265 pmapproc_getport(struct svc_req *rqstp __unused, SVCXPRT *xprt) 266 { 267 struct pmap reg; 268 long lport; 269 int port = 0; 270 struct 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 280 if (!check_access(xprt, PMAPPROC_GETPORT, ®, PMAPVERS)) { 281 svcerr_weakauth(xprt); 282 return FALSE; 283 } 284 285 #ifdef RPCBIND_DEBUG 286 if (debugging) { 287 uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid), 288 svc_getrpccaller(xprt)); 289 fprintf(stderr, "PMAP_GETPORT req for (%lu, %lu, %s) from %s :", 290 reg.pm_prog, reg.pm_vers, 291 reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr); 292 free(uaddr); 293 } 294 #endif 295 fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot); 296 if (fnd) { 297 char serveuaddr[32], *ua; 298 int h1, h2, h3, h4, p1, p2; 299 char *netid; 300 301 if (reg.pm_prot == IPPROTO_UDP) { 302 ua = udp_uaddr; 303 netid = udptrans; 304 } else { 305 ua = tcp_uaddr; /* To get the len */ 306 netid = tcptrans; 307 } 308 if (ua == NULL) { 309 goto sendreply; 310 } 311 if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, 312 &h4, &p1, &p2) == 6) { 313 p1 = (fnd->pml_map.pm_port >> 8) & 0xff; 314 p2 = (fnd->pml_map.pm_port) & 0xff; 315 snprintf(serveuaddr, sizeof serveuaddr, 316 "%d.%d.%d.%d.%d.%d", h1, h2, h3, h4, p1, p2); 317 if (is_bound(netid, serveuaddr)) { 318 port = fnd->pml_map.pm_port; 319 } else { /* this service is dead; delete it */ 320 delete_prog(reg.pm_prog); 321 } 322 } 323 } 324 sendreply: 325 lport = port; 326 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&lport)) && 327 debugging) { 328 (void) fprintf(stderr, "portmap: svc_sendreply\n"); 329 if (doabort) { 330 rpcbind_abort(); 331 } 332 } 333 #ifdef RPCBIND_DEBUG 334 if (debugging) 335 fprintf(stderr, "port = %d\n", port); 336 #endif 337 rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers, 338 reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans, 339 port ? udptrans : ""); 340 341 return (TRUE); 342 } 343 344 /* ARGSUSED */ 345 static bool_t 346 pmapproc_dump(struct svc_req *rqstp __unused, SVCXPRT *xprt) 347 { 348 if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) { 349 svcerr_decode(xprt); 350 return (FALSE); 351 } 352 353 if (!check_access(xprt, PMAPPROC_DUMP, NULL, PMAPVERS)) { 354 svcerr_weakauth(xprt); 355 return FALSE; 356 } 357 358 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist_ptr, 359 (caddr_t)&list_pml)) && debugging) { 360 if (debugging) 361 (void) fprintf(stderr, "portmap: svc_sendreply\n"); 362 if (doabort) { 363 rpcbind_abort(); 364 } 365 } 366 return (TRUE); 367 } 368 369 #endif /* PORTMAP */ 370