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