1 /* 2 * Copyright (c) 1984 by Sun Microsystems, Inc. 3 * 4 * @(#)portmap.c 5.1 (Berkeley) 08/23/90 5 */ 6 7 /* @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC */ 8 #ifndef lint 9 static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro"; 10 #endif 11 12 /* 13 * portmap.c, Implements the program,version to port number mapping for 14 * rpc. 15 */ 16 17 /* 18 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 19 * unrestricted use provided that this legend is included on all tape 20 * media and as a part of the software program in whole or part. Users 21 * may copy or modify Sun RPC without charge, but are not authorized 22 * to license or distribute it to anyone else except as part of a product or 23 * program developed by the user. 24 * 25 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 26 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 28 * 29 * Sun RPC is provided with no support and without any obligation on the 30 * part of Sun Microsystems, Inc. to assist in its use, correction, 31 * modification or enhancement. 32 * 33 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 34 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 35 * OR ANY PART THEREOF. 36 * 37 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 38 * or profits or other special, indirect and consequential damages, even if 39 * Sun has been advised of the possibility of such damages. 40 * 41 * Sun Microsystems, Inc. 42 * 2550 Garcia Avenue 43 * Mountain View, California 94043 44 */ 45 46 #include <rpc/rpc.h> 47 #include <rpc/pmap_prot.h> 48 #include <stdio.h> 49 #include <netdb.h> 50 #include <sys/socket.h> 51 #include <sys/ioctl.h> 52 #include <sys/wait.h> 53 #include <sys/signal.h> 54 55 char *malloc(); 56 int reg_service(); 57 void reap(); 58 struct pmaplist *pmaplist; 59 static int debugging = 0; 60 61 main() 62 { 63 SVCXPRT *xprt; 64 int sock, pid, t; 65 struct sockaddr_in addr; 66 int len = sizeof(struct sockaddr_in); 67 register struct pmaplist *pml; 68 69 #ifndef DEBUG 70 pid = fork(); 71 if (pid < 0) { 72 perror("portmap: fork"); 73 exit(1); 74 } 75 if (pid != 0) 76 exit(0); 77 for (t = 0; t < 20; t++) 78 close(t); 79 open("/", 0); 80 dup2(0, 1); 81 dup2(0, 2); 82 t = open("/dev/tty", 2); 83 if (t >= 0) { 84 ioctl(t, TIOCNOTTY, (char *)0); 85 close(t); 86 } 87 #endif 88 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 89 perror("portmap cannot create socket"); 90 exit(1); 91 } 92 93 addr.sin_addr.s_addr = 0; 94 addr.sin_family = AF_INET; 95 addr.sin_port = htons(PMAPPORT); 96 if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 97 perror("portmap cannot bind"); 98 exit(1); 99 } 100 101 if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { 102 fprintf(stderr, "couldn't do udp_create\n"); 103 exit(1); 104 } 105 /* make an entry for ourself */ 106 pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); 107 pml->pml_next = 0; 108 pml->pml_map.pm_prog = PMAPPROG; 109 pml->pml_map.pm_vers = PMAPVERS; 110 pml->pml_map.pm_prot = IPPROTO_UDP; 111 pml->pml_map.pm_port = PMAPPORT; 112 pmaplist = pml; 113 114 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 115 perror("portmap cannot create socket"); 116 exit(1); 117 } 118 if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 119 perror("portmap cannot bind"); 120 exit(1); 121 } 122 if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) 123 == (SVCXPRT *)NULL) { 124 fprintf(stderr, "couldn't do tcp_create\n"); 125 exit(1); 126 } 127 /* make an entry for ourself */ 128 pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); 129 pml->pml_map.pm_prog = PMAPPROG; 130 pml->pml_map.pm_vers = PMAPVERS; 131 pml->pml_map.pm_prot = IPPROTO_TCP; 132 pml->pml_map.pm_port = PMAPPORT; 133 pml->pml_next = pmaplist; 134 pmaplist = pml; 135 136 (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE); 137 138 (void)signal(SIGCHLD, reap); 139 svc_run(); 140 fprintf(stderr, "run_svc returned unexpectedly\n"); 141 abort(); 142 } 143 144 static struct pmaplist * 145 find_service(prog, vers, prot) 146 u_long prog; 147 u_long vers; 148 { 149 register struct pmaplist *hit = NULL; 150 register struct pmaplist *pml; 151 152 for (pml = pmaplist; 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 return (hit); 161 } 162 163 /* 164 * 1 OK, 0 not 165 */ 166 reg_service(rqstp, xprt) 167 struct svc_req *rqstp; 168 SVCXPRT *xprt; 169 { 170 struct pmap reg; 171 struct pmaplist *pml, *prevpml, *fnd; 172 int ans, port; 173 caddr_t t; 174 175 #ifdef DEBUG 176 fprintf(stderr, "server: about do a switch\n"); 177 #endif 178 switch (rqstp->rq_proc) { 179 180 case PMAPPROC_NULL: 181 /* 182 * Null proc call 183 */ 184 if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) { 185 abort(); 186 } 187 break; 188 189 case PMAPPROC_SET: 190 /* 191 * Set a program,version to port mapping 192 */ 193 if (!svc_getargs(xprt, xdr_pmap, ®)) 194 svcerr_decode(xprt); 195 else { 196 /* 197 * check to see if already used 198 * find_service returns a hit even if 199 * the versions don't match, so check for it 200 */ 201 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 202 if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { 203 if (fnd->pml_map.pm_port == reg.pm_port) { 204 ans = 1; 205 goto done; 206 } 207 else { 208 ans = 0; 209 goto done; 210 } 211 } else { 212 /* 213 * add to END of list 214 */ 215 pml = (struct pmaplist *) 216 malloc((u_int)sizeof(struct pmaplist)); 217 pml->pml_map = reg; 218 pml->pml_next = 0; 219 if (pmaplist == 0) { 220 pmaplist = pml; 221 } else { 222 for (fnd= pmaplist; fnd->pml_next != 0; 223 fnd = fnd->pml_next); 224 fnd->pml_next = pml; 225 } 226 ans = 1; 227 } 228 done: 229 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 230 debugging) { 231 fprintf(stderr, "svc_sendreply\n"); 232 abort(); 233 } 234 } 235 break; 236 237 case PMAPPROC_UNSET: 238 /* 239 * Remove a program,version to port mapping. 240 */ 241 if (!svc_getargs(xprt, xdr_pmap, ®)) 242 svcerr_decode(xprt); 243 else { 244 ans = 0; 245 for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { 246 if ((pml->pml_map.pm_prog != reg.pm_prog) || 247 (pml->pml_map.pm_vers != reg.pm_vers)) { 248 /* both pml & prevpml move forwards */ 249 prevpml = pml; 250 pml = pml->pml_next; 251 continue; 252 } 253 /* found it; pml moves forward, prevpml stays */ 254 ans = 1; 255 t = (caddr_t)pml; 256 pml = pml->pml_next; 257 if (prevpml == NULL) 258 pmaplist = pml; 259 else 260 prevpml->pml_next = pml; 261 free(t); 262 } 263 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 264 debugging) { 265 fprintf(stderr, "svc_sendreply\n"); 266 abort(); 267 } 268 } 269 break; 270 271 case PMAPPROC_GETPORT: 272 /* 273 * Lookup the mapping for a program,version and return its port 274 */ 275 if (!svc_getargs(xprt, xdr_pmap, ®)) 276 svcerr_decode(xprt); 277 else { 278 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 279 if (fnd) 280 port = fnd->pml_map.pm_port; 281 else 282 port = 0; 283 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && 284 debugging) { 285 fprintf(stderr, "svc_sendreply\n"); 286 abort(); 287 } 288 } 289 break; 290 291 case PMAPPROC_DUMP: 292 /* 293 * Return the current set of mapped program,version 294 */ 295 if (!svc_getargs(xprt, xdr_void, NULL)) 296 svcerr_decode(xprt); 297 else { 298 if ((!svc_sendreply(xprt, xdr_pmaplist, 299 (caddr_t)&pmaplist)) && debugging) { 300 fprintf(stderr, "svc_sendreply\n"); 301 abort(); 302 } 303 } 304 break; 305 306 case PMAPPROC_CALLIT: 307 /* 308 * Calls a procedure on the local machine. If the requested 309 * procedure is not registered this procedure does not return 310 * error information!! 311 * This procedure is only supported on rpc/udp and calls via 312 * rpc/udp. It passes null authentication parameters. 313 */ 314 callit(rqstp, xprt); 315 break; 316 317 default: 318 svcerr_noproc(xprt); 319 break; 320 } 321 } 322 323 324 /* 325 * Stuff for the rmtcall service 326 */ 327 #define ARGSIZE 9000 328 329 typedef struct encap_parms { 330 u_long arglen; 331 char *args; 332 }; 333 334 static bool_t 335 xdr_encap_parms(xdrs, epp) 336 XDR *xdrs; 337 struct encap_parms *epp; 338 { 339 340 return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); 341 } 342 343 typedef struct rmtcallargs { 344 u_long rmt_prog; 345 u_long rmt_vers; 346 u_long rmt_port; 347 u_long rmt_proc; 348 struct encap_parms rmt_args; 349 }; 350 351 static bool_t 352 xdr_rmtcall_args(xdrs, cap) 353 register XDR *xdrs; 354 register struct rmtcallargs *cap; 355 { 356 357 /* does not get a port number */ 358 if (xdr_u_long(xdrs, &(cap->rmt_prog)) && 359 xdr_u_long(xdrs, &(cap->rmt_vers)) && 360 xdr_u_long(xdrs, &(cap->rmt_proc))) { 361 return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 362 } 363 return (FALSE); 364 } 365 366 static bool_t 367 xdr_rmtcall_result(xdrs, cap) 368 register XDR *xdrs; 369 register struct rmtcallargs *cap; 370 { 371 if (xdr_u_long(xdrs, &(cap->rmt_port))) 372 return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 373 return (FALSE); 374 } 375 376 /* 377 * only worries about the struct encap_parms part of struct rmtcallargs. 378 * The arglen must already be set!! 379 */ 380 static bool_t 381 xdr_opaque_parms(xdrs, cap) 382 XDR *xdrs; 383 struct rmtcallargs *cap; 384 { 385 386 return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); 387 } 388 389 /* 390 * This routine finds and sets the length of incoming opaque paraters 391 * and then calls xdr_opaque_parms. 392 */ 393 static bool_t 394 xdr_len_opaque_parms(xdrs, cap) 395 register XDR *xdrs; 396 struct rmtcallargs *cap; 397 { 398 register u_int beginpos, lowpos, highpos, currpos, pos; 399 400 beginpos = lowpos = pos = xdr_getpos(xdrs); 401 highpos = lowpos + ARGSIZE; 402 while ((int)(highpos - lowpos) >= 0) { 403 currpos = (lowpos + highpos) / 2; 404 if (xdr_setpos(xdrs, currpos)) { 405 pos = currpos; 406 lowpos = currpos + 1; 407 } else { 408 highpos = currpos - 1; 409 } 410 } 411 xdr_setpos(xdrs, beginpos); 412 cap->rmt_args.arglen = pos - beginpos; 413 return (xdr_opaque_parms(xdrs, cap)); 414 } 415 416 /* 417 * Call a remote procedure service 418 * This procedure is very quiet when things go wrong. 419 * The proc is written to support broadcast rpc. In the broadcast case, 420 * a machine should shut-up instead of complain, less the requestor be 421 * overrun with complaints at the expense of not hearing a valid reply ... 422 * 423 * This now forks so that the program & process that it calls can call 424 * back to the portmapper. 425 */ 426 static 427 callit(rqstp, xprt) 428 struct svc_req *rqstp; 429 SVCXPRT *xprt; 430 { 431 struct rmtcallargs a; 432 struct pmaplist *pml; 433 u_short port; 434 struct sockaddr_in me; 435 int pid, socket = -1; 436 CLIENT *client; 437 struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; 438 struct timeval timeout; 439 char buf[ARGSIZE]; 440 441 timeout.tv_sec = 5; 442 timeout.tv_usec = 0; 443 a.rmt_args.args = buf; 444 if (!svc_getargs(xprt, xdr_rmtcall_args, &a)) 445 return; 446 if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL) 447 return; 448 /* 449 * fork a child to do the work. Parent immediately returns. 450 * Child exits upon completion. 451 */ 452 if ((pid = fork()) != 0) { 453 if (debugging && (pid < 0)) { 454 fprintf(stderr, "portmap CALLIT: cannot fork.\n"); 455 } 456 return; 457 } 458 port = pml->pml_map.pm_port; 459 get_myaddress(&me); 460 me.sin_port = htons(port); 461 client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket); 462 if (client != (CLIENT *)NULL) { 463 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { 464 client->cl_auth = authunix_create(au->aup_machname, 465 au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); 466 } 467 a.rmt_port = (u_long)port; 468 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, 469 xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) { 470 svc_sendreply(xprt, xdr_rmtcall_result, &a); 471 } 472 AUTH_DESTROY(client->cl_auth); 473 clnt_destroy(client); 474 } 475 (void)close(socket); 476 exit(0); 477 } 478 479 void 480 reap() 481 { 482 while (wait3(NULL, WNOHANG, NULL) > 0); 483 } 484