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