1 /* @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC */
3 static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
7 * Copyright (c) 1984 by Sun Microsystems, Inc.
11 * portmap.c, Implements the program,version to port number mapping for
16 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
17 * unrestricted use provided that this legend is included on all tape
18 * media and as a part of the software program in whole or part. Users
19 * may copy or modify Sun RPC without charge, but are not authorized
20 * to license or distribute it to anyone else except as part of a product or
21 * program developed by the user.
23 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
24 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
27 * Sun RPC is provided with no support and without any obligation on the
28 * part of Sun Microsystems, Inc. to assist in its use, correction,
29 * modification or enhancement.
31 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
32 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
33 * OR ANY PART THEREOF.
35 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
36 * or profits or other special, indirect and consequential damages, even if
37 * Sun has been advised of the possibility of such damages.
39 * Sun Microsystems, Inc.
41 * Mountain View, California 94043
45 #include <rpc/pmap_prot.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
51 #include <sys/signal.h>
56 struct pmaplist *pmaplist;
57 static int debugging = 0;
63 struct sockaddr_in addr;
64 int len = sizeof(struct sockaddr_in);
65 register struct pmaplist *pml;
70 perror("portmap: fork");
75 for (t = 0; t < 20; t++)
80 t = open("/dev/tty", 2);
82 ioctl(t, TIOCNOTTY, (char *)0);
86 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
87 perror(_("portmap cannot create socket"));
91 addr.sin_addr.s_addr = 0;
92 addr.sin_family = AF_INET;
93 addr.sin_port = htons(PMAPPORT);
94 if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
95 perror(_("portmap cannot bind"));
99 if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
100 fprintf(stderr, _("couldn't do udp_create\n"));
103 /* make an entry for ourself */
104 pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
106 pml->pml_map.pm_prog = PMAPPROG;
107 pml->pml_map.pm_vers = PMAPVERS;
108 pml->pml_map.pm_prot = IPPROTO_UDP;
109 pml->pml_map.pm_port = PMAPPORT;
112 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
113 perror(_("portmap cannot create socket"));
116 if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
117 perror(_("portmap cannot bind"));
120 if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
121 == (SVCXPRT *)NULL) {
122 fprintf(stderr, _("couldn't do tcp_create\n"));
125 /* make an entry for ourself */
126 pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
127 pml->pml_map.pm_prog = PMAPPROG;
128 pml->pml_map.pm_vers = PMAPVERS;
129 pml->pml_map.pm_prot = IPPROTO_TCP;
130 pml->pml_map.pm_port = PMAPPORT;
131 pml->pml_next = pmaplist;
134 (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
136 (void)signal(SIGCHLD, reap);
138 fprintf(stderr, _("run_svc returned unexpectedly\n"));
142 static struct pmaplist *
143 find_service(prog, vers, prot)
147 register struct pmaplist *hit = NULL;
148 register struct pmaplist *pml;
150 for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
151 if ((pml->pml_map.pm_prog != prog) ||
152 (pml->pml_map.pm_prot != prot))
155 if (pml->pml_map.pm_vers == vers)
164 reg_service(rqstp, xprt)
165 struct svc_req *rqstp;
169 struct pmaplist *pml, *prevpml, *fnd;
174 fprintf(stderr, "server: about do a switch\n");
176 switch (rqstp->rq_proc) {
182 if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
189 * Set a program,version to port mapping
191 if (!svc_getargs(xprt, xdr_pmap, ®))
195 * check to see if already used
196 * find_service returns a hit even if
197 * the versions don't match, so check for it
199 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
200 if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
201 if (fnd->pml_map.pm_port == reg.pm_port) {
213 pml = (struct pmaplist *)
214 malloc((u_int)sizeof(struct pmaplist));
220 for (fnd= pmaplist; fnd->pml_next != 0;
221 fnd = fnd->pml_next);
227 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
229 fprintf(stderr, "svc_sendreply\n");
237 * Remove a program,version to port mapping.
239 if (!svc_getargs(xprt, xdr_pmap, ®))
243 for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
244 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
245 (pml->pml_map.pm_vers != reg.pm_vers)) {
246 /* both pml & prevpml move forwards */
251 /* found it; pml moves forward, prevpml stays */
258 prevpml->pml_next = pml;
261 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
263 fprintf(stderr, "svc_sendreply\n");
269 case PMAPPROC_GETPORT:
271 * Lookup the mapping for a program,version and return its port
273 if (!svc_getargs(xprt, xdr_pmap, ®))
276 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
278 port = fnd->pml_map.pm_port;
281 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
283 fprintf(stderr, "svc_sendreply\n");
291 * Return the current set of mapped program,version
293 if (!svc_getargs(xprt, xdr_void, NULL))
296 if ((!svc_sendreply(xprt, xdr_pmaplist,
297 (caddr_t)&pmaplist)) && debugging) {
298 fprintf(stderr, "svc_sendreply\n");
304 case PMAPPROC_CALLIT:
306 * Calls a procedure on the local machine. If the requested
307 * procedure is not registered this procedure does not return
308 * error information!!
309 * This procedure is only supported on rpc/udp and calls via
310 * rpc/udp. It passes null authentication parameters.
323 * Stuff for the rmtcall service
327 typedef struct encap_parms {
333 xdr_encap_parms(xdrs, epp)
335 struct encap_parms *epp;
338 return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
341 typedef struct rmtcallargs {
346 struct encap_parms rmt_args;
350 xdr_rmtcall_args(xdrs, cap)
352 register struct rmtcallargs *cap;
355 /* does not get a port number */
356 if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
357 xdr_u_long(xdrs, &(cap->rmt_vers)) &&
358 xdr_u_long(xdrs, &(cap->rmt_proc))) {
359 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
365 xdr_rmtcall_result(xdrs, cap)
367 register struct rmtcallargs *cap;
369 if (xdr_u_long(xdrs, &(cap->rmt_port)))
370 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
375 * only worries about the struct encap_parms part of struct rmtcallargs.
376 * The arglen must already be set!!
379 xdr_opaque_parms(xdrs, cap)
381 struct rmtcallargs *cap;
384 return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
388 * This routine finds and sets the length of incoming opaque paraters
389 * and then calls xdr_opaque_parms.
392 xdr_len_opaque_parms(xdrs, cap)
394 struct rmtcallargs *cap;
396 register u_int beginpos, lowpos, highpos, currpos, pos;
398 beginpos = lowpos = pos = xdr_getpos(xdrs);
399 highpos = lowpos + ARGSIZE;
400 while ((int)(highpos - lowpos) >= 0) {
401 currpos = (lowpos + highpos) / 2;
402 if (xdr_setpos(xdrs, currpos)) {
404 lowpos = currpos + 1;
406 highpos = currpos - 1;
409 xdr_setpos(xdrs, beginpos);
410 cap->rmt_args.arglen = pos - beginpos;
411 return (xdr_opaque_parms(xdrs, cap));
415 * Call a remote procedure service
416 * This procedure is very quiet when things go wrong.
417 * The proc is written to support broadcast rpc. In the broadcast case,
418 * a machine should shut-up instead of complain, less the requestor be
419 * overrun with complaints at the expense of not hearing a valid reply ...
421 * This now forks so that the program & process that it calls can call
422 * back to the portmapper.
426 struct svc_req *rqstp;
429 struct rmtcallargs a;
430 struct pmaplist *pml;
432 struct sockaddr_in me;
433 int pid, socket = -1;
435 struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
436 struct timeval timeout;
441 a.rmt_args.args = buf;
442 if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
444 if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
447 * fork a child to do the work. Parent immediately returns.
448 * Child exits upon completion.
450 if ((pid = fork()) != 0) {
451 if (debugging && (pid < 0)) {
452 fprintf(stderr, _("portmap CALLIT: cannot fork.\n"));
456 port = pml->pml_map.pm_port;
458 me.sin_port = htons(port);
459 client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
460 if (client != (CLIENT *)NULL) {
461 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
462 client->cl_auth = authunix_create(au->aup_machname,
463 au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
465 a.rmt_port = (u_long)port;
466 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
467 xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
468 svc_sendreply(xprt, xdr_rmtcall_result, &a);
470 AUTH_DESTROY(client->cl_auth);
471 clnt_destroy(client);
480 while (wait3(NULL, WNOHANG, NULL) > 0);