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