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