1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 * 29 * @(#)pmap_svc.c 1.14 93/07/05 SMI; 1.23 89/04/05 Copyr 1984 Sun Micro 30 * $NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $ 31 * $FreeBSD: src/usr.sbin/rpcbind/pmap_svc.c,v 1.5 2007/11/07 10:53:39 kevlo Exp $ 32 * $DragonFly$ 33 */ 34 /* 35 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. 36 */ 37 38 /* 39 * pmap_svc.c 40 * The server procedure for the version 2 portmaper. 41 * All the portmapper related interface from the portmap side. 42 */ 43 44 #ifdef PORTMAP 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <stdio.h> 48 #include <rpc/rpc.h> 49 #include <rpc/pmap_prot.h> 50 #include <rpc/rpcb_prot.h> 51 #ifdef RPCBIND_DEBUG 52 #include <stdlib.h> 53 #endif 54 #include "rpcbind.h" 55 56 static struct pmaplist *find_service_pmap(rpcprog_t, rpcvers_t, rpcprot_t); 57 static bool_t pmapproc_change(struct svc_req *, SVCXPRT *, u_long); 58 static bool_t pmapproc_getport(struct svc_req *, SVCXPRT *); 59 static bool_t pmapproc_dump(struct svc_req *, SVCXPRT *); 60 61 /* 62 * Called for all the version 2 inquiries. 63 */ 64 void 65 pmap_service(struct svc_req *rqstp, SVCXPRT *xprt) 66 { 67 rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc); 68 switch (rqstp->rq_proc) { 69 case PMAPPROC_NULL: 70 /* 71 * Null proc call 72 */ 73 #ifdef RPCBIND_DEBUG 74 if (debugging) 75 fprintf(stderr, "PMAPPROC_NULL\n"); 76 #endif 77 check_access(xprt, rqstp->rq_proc, NULL, PMAPVERS); 78 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) && 79 debugging) { 80 if (doabort) { 81 rpcbind_abort(); 82 } 83 } 84 break; 85 86 case PMAPPROC_SET: 87 /* 88 * Set a program, version to port mapping 89 */ 90 pmapproc_change(rqstp, xprt, rqstp->rq_proc); 91 break; 92 93 case PMAPPROC_UNSET: 94 /* 95 * Remove a program, version to port mapping. 96 */ 97 pmapproc_change(rqstp, xprt, rqstp->rq_proc); 98 break; 99 100 case PMAPPROC_GETPORT: 101 /* 102 * Lookup the mapping for a program, version and return its 103 * port number. 104 */ 105 pmapproc_getport(rqstp, xprt); 106 break; 107 108 case PMAPPROC_DUMP: 109 /* 110 * Return the current set of mapped program, version 111 */ 112 #ifdef RPCBIND_DEBUG 113 if (debugging) 114 fprintf(stderr, "PMAPPROC_DUMP\n"); 115 #endif 116 pmapproc_dump(rqstp, xprt); 117 break; 118 119 case PMAPPROC_CALLIT: 120 /* 121 * Calls a procedure on the local machine. If the requested 122 * procedure is not registered this procedure does not return 123 * error information!! 124 * This procedure is only supported on rpc/udp and calls via 125 * rpc/udp. It passes null authentication parameters. 126 */ 127 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS); 128 break; 129 130 default: 131 svcerr_noproc(xprt); 132 break; 133 } 134 } 135 136 /* 137 * returns the item with the given program, version number. If that version 138 * number is not found, it returns the item with that program number, so that 139 * the port number is now returned to the caller. The caller when makes a 140 * call to this program, version number, the call will fail and it will 141 * return with PROGVERS_MISMATCH. The user can then determine the highest 142 * and the lowest version number for this program using clnt_geterr() and 143 * use those program version numbers. 144 */ 145 static struct pmaplist * 146 find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot) 147 { 148 struct pmaplist *hit = NULL; 149 struct pmaplist *pml; 150 151 for (pml = list_pml; pml != NULL; pml = pml->pml_next) { 152 if ((pml->pml_map.pm_prog != prog) || 153 (pml->pml_map.pm_prot != prot)) 154 continue; 155 hit = pml; 156 if (pml->pml_map.pm_vers == vers) 157 break; 158 } 159 return (hit); 160 } 161 162 static bool_t 163 pmapproc_change(struct svc_req *rqstp __unused, SVCXPRT *xprt, unsigned long op) 164 { 165 struct pmap reg; 166 RPCB rpcbreg; 167 long ans; 168 struct sockaddr_in *who; 169 uid_t uid; 170 char uidbuf[32]; 171 172 #ifdef RPCBIND_DEBUG 173 if (debugging) 174 fprintf(stderr, "%s request for (%lu, %lu) : ", 175 op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET", 176 reg.pm_prog, reg.pm_vers); 177 #endif 178 179 if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)®)) { 180 svcerr_decode(xprt); 181 return (FALSE); 182 } 183 184 if (!check_access(xprt, op, ®, PMAPVERS)) { 185 svcerr_weakauth(xprt); 186 return FALSE; 187 } 188 189 who = svc_getcaller(xprt); 190 191 /* 192 * Can't use getpwnam here. We might end up calling ourselves 193 * and looping. 194 */ 195 if (__rpc_get_local_uid(xprt, &uid) < 0) 196 rpcbreg.r_owner = "unknown"; 197 else if (uid == 0) 198 rpcbreg.r_owner = "superuser"; 199 else { 200 /* r_owner will be strdup-ed later */ 201 snprintf(uidbuf, sizeof uidbuf, "%d", uid); 202 rpcbreg.r_owner = uidbuf; 203 } 204 205 rpcbreg.r_prog = reg.pm_prog; 206 rpcbreg.r_vers = reg.pm_vers; 207 208 if (op == PMAPPROC_SET) { 209 char buf[32]; 210 211 snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", 212 (int)((reg.pm_port >> 8) & 0xff), 213 (int)(reg.pm_port & 0xff)); 214 rpcbreg.r_addr = buf; 215 if (reg.pm_prot == IPPROTO_UDP) { 216 rpcbreg.r_netid = udptrans; 217 } else if (reg.pm_prot == IPPROTO_TCP) { 218 rpcbreg.r_netid = tcptrans; 219 } else { 220 ans = FALSE; 221 goto done_change; 222 } 223 ans = map_set(&rpcbreg, rpcbreg.r_owner); 224 } else if (op == PMAPPROC_UNSET) { 225 bool_t ans1, ans2; 226 227 rpcbreg.r_addr = NULL; 228 rpcbreg.r_netid = tcptrans; 229 ans1 = map_unset(&rpcbreg, rpcbreg.r_owner); 230 rpcbreg.r_netid = udptrans; 231 ans2 = map_unset(&rpcbreg, rpcbreg.r_owner); 232 ans = ans1 || ans2; 233 } else { 234 ans = FALSE; 235 } 236 done_change: 237 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t) &ans)) && 238 debugging) { 239 fprintf(stderr, "portmap: svc_sendreply\n"); 240 if (doabort) { 241 rpcbind_abort(); 242 } 243 } 244 #ifdef RPCBIND_DEBUG 245 if (debugging) 246 fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed"); 247 #endif 248 if (op == PMAPPROC_SET) 249 rpcbs_set(RPCBVERS_2_STAT, ans); 250 else 251 rpcbs_unset(RPCBVERS_2_STAT, ans); 252 return (TRUE); 253 } 254 255 /* ARGSUSED */ 256 static bool_t 257 pmapproc_getport(struct svc_req *rqstp __unused, SVCXPRT *xprt) 258 { 259 struct pmap reg; 260 long lport; 261 int port = 0; 262 struct pmaplist *fnd; 263 #ifdef RPCBIND_DEBUG 264 char *uaddr; 265 #endif 266 267 if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)®)) { 268 svcerr_decode(xprt); 269 return (FALSE); 270 } 271 272 if (!check_access(xprt, PMAPPROC_GETPORT, ®, PMAPVERS)) { 273 svcerr_weakauth(xprt); 274 return FALSE; 275 } 276 277 #ifdef RPCBIND_DEBUG 278 if (debugging) { 279 uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid), 280 svc_getrpccaller(xprt)); 281 fprintf(stderr, "PMAP_GETPORT req for (%lu, %lu, %s) from %s :", 282 reg.pm_prog, reg.pm_vers, 283 reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr); 284 free(uaddr); 285 } 286 #endif 287 fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot); 288 if (fnd) { 289 char serveuaddr[32], *ua; 290 int h1, h2, h3, h4, p1, p2; 291 char *netid; 292 293 if (reg.pm_prot == IPPROTO_UDP) { 294 ua = udp_uaddr; 295 netid = udptrans; 296 } else { 297 ua = tcp_uaddr; /* To get the len */ 298 netid = tcptrans; 299 } 300 if (ua == NULL) { 301 goto sendreply; 302 } 303 if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, 304 &h4, &p1, &p2) == 6) { 305 p1 = (fnd->pml_map.pm_port >> 8) & 0xff; 306 p2 = (fnd->pml_map.pm_port) & 0xff; 307 snprintf(serveuaddr, sizeof serveuaddr, 308 "%d.%d.%d.%d.%d.%d", h1, h2, h3, h4, p1, p2); 309 if (is_bound(netid, serveuaddr)) { 310 port = fnd->pml_map.pm_port; 311 } else { /* this service is dead; delete it */ 312 delete_prog(reg.pm_prog); 313 } 314 } 315 } 316 sendreply: 317 lport = port; 318 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&lport)) && 319 debugging) { 320 fprintf(stderr, "portmap: svc_sendreply\n"); 321 if (doabort) { 322 rpcbind_abort(); 323 } 324 } 325 #ifdef RPCBIND_DEBUG 326 if (debugging) 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(struct svc_req *rqstp __unused, SVCXPRT *xprt) 339 { 340 if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) { 341 svcerr_decode(xprt); 342 return (FALSE); 343 } 344 345 if (!check_access(xprt, PMAPPROC_DUMP, NULL, PMAPVERS)) { 346 svcerr_weakauth(xprt); 347 return FALSE; 348 } 349 350 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist_ptr, 351 (caddr_t)&list_pml)) && debugging) { 352 if (debugging) 353 fprintf(stderr, "portmap: svc_sendreply\n"); 354 if (doabort) { 355 rpcbind_abort(); 356 } 357 } 358 return (TRUE); 359 } 360 361 #endif /* PORTMAP */ 362