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