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