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>
55 struct pmaplist
*pmaplist
;
56 static int debugging
= 0;
62 struct sockaddr_in addr
;
63 int len
= sizeof(struct sockaddr_in
);
64 register struct pmaplist
*pml
;
69 perror("portmap: fork");
74 for (t
= 0; t
< 20; t
++)
79 t
= open("/dev/tty", 2);
81 ioctl(t
, TIOCNOTTY
, (char *)0);
85 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
86 perror(_("portmap cannot create socket"));
90 addr
.sin_addr
.s_addr
= 0;
91 addr
.sin_family
= AF_INET
;
92 addr
.sin_port
= htons(PMAPPORT
);
93 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
94 perror(_("portmap cannot bind"));
98 if ((xprt
= svcudp_create(sock
)) == (SVCXPRT
*)NULL
) {
99 fprintf(stderr
, _("couldn't do udp_create\n"));
102 /* make an entry for ourself */
103 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
105 pml
->pml_map
.pm_prog
= PMAPPROG
;
106 pml
->pml_map
.pm_vers
= PMAPVERS
;
107 pml
->pml_map
.pm_prot
= IPPROTO_UDP
;
108 pml
->pml_map
.pm_port
= PMAPPORT
;
111 if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) < 0) {
112 perror(_("portmap cannot create socket"));
115 if (bind(sock
, (struct sockaddr
*)&addr
, len
) != 0) {
116 perror(_("portmap cannot bind"));
119 if ((xprt
= svctcp_create(sock
, RPCSMALLMSGSIZE
, RPCSMALLMSGSIZE
))
120 == (SVCXPRT
*)NULL
) {
121 fprintf(stderr
, _("couldn't do tcp_create\n"));
124 /* make an entry for ourself */
125 pml
= (struct pmaplist
*)malloc((u_int
)sizeof(struct pmaplist
));
126 pml
->pml_map
.pm_prog
= PMAPPROG
;
127 pml
->pml_map
.pm_vers
= PMAPVERS
;
128 pml
->pml_map
.pm_prot
= IPPROTO_TCP
;
129 pml
->pml_map
.pm_port
= PMAPPORT
;
130 pml
->pml_next
= pmaplist
;
133 (void)svc_register(xprt
, PMAPPROG
, PMAPVERS
, reg_service
, FALSE
);
135 (void)signal(SIGCHLD
, reap
);
137 fprintf(stderr
, _("run_svc returned unexpectedly\n"));
141 static struct pmaplist
*
142 find_service(prog
, vers
, prot
)
146 register struct pmaplist
*hit
= NULL
;
147 register struct pmaplist
*pml
;
149 for (pml
= pmaplist
; pml
!= NULL
; pml
= pml
->pml_next
) {
150 if ((pml
->pml_map
.pm_prog
!= prog
) ||
151 (pml
->pml_map
.pm_prot
!= prot
))
154 if (pml
->pml_map
.pm_vers
== vers
)
163 reg_service(rqstp
, xprt
)
164 struct svc_req
*rqstp
;
168 struct pmaplist
*pml
, *prevpml
, *fnd
;
173 fprintf(stderr
, "server: about do a switch\n");
175 switch (rqstp
->rq_proc
) {
181 if ((!svc_sendreply(xprt
, xdr_void
, NULL
)) && debugging
) {
188 * Set a program,version to port mapping
190 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
194 * check to see if already used
195 * find_service returns a hit even if
196 * the versions don't match, so check for it
198 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
199 if (fnd
&& fnd
->pml_map
.pm_vers
== reg
.pm_vers
) {
200 if (fnd
->pml_map
.pm_port
== reg
.pm_port
) {
212 pml
= (struct pmaplist
*)
213 malloc((u_int
)sizeof(struct pmaplist
));
219 for (fnd
= pmaplist
; fnd
->pml_next
!= 0;
220 fnd
= fnd
->pml_next
);
226 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
228 fprintf(stderr
, "svc_sendreply\n");
236 * Remove a program,version to port mapping.
238 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
242 for (prevpml
= NULL
, pml
= pmaplist
; pml
!= NULL
; ) {
243 if ((pml
->pml_map
.pm_prog
!= reg
.pm_prog
) ||
244 (pml
->pml_map
.pm_vers
!= reg
.pm_vers
)) {
245 /* both pml & prevpml move forwards */
250 /* found it; pml moves forward, prevpml stays */
257 prevpml
->pml_next
= pml
;
260 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&ans
)) &&
262 fprintf(stderr
, "svc_sendreply\n");
268 case PMAPPROC_GETPORT
:
270 * Lookup the mapping for a program,version and return its port
272 if (!svc_getargs(xprt
, xdr_pmap
, ®
))
275 fnd
= find_service(reg
.pm_prog
, reg
.pm_vers
, reg
.pm_prot
);
277 port
= fnd
->pml_map
.pm_port
;
280 if ((!svc_sendreply(xprt
, xdr_long
, (caddr_t
)&port
)) &&
282 fprintf(stderr
, "svc_sendreply\n");
290 * Return the current set of mapped program,version
292 if (!svc_getargs(xprt
, xdr_void
, NULL
))
295 if ((!svc_sendreply(xprt
, xdr_pmaplist
,
296 (caddr_t
)&pmaplist
)) && debugging
) {
297 fprintf(stderr
, "svc_sendreply\n");
303 case PMAPPROC_CALLIT
:
305 * Calls a procedure on the local machine. If the requested
306 * procedure is not registered this procedure does not return
307 * error information!!
308 * This procedure is only supported on rpc/udp and calls via
309 * rpc/udp. It passes null authentication parameters.
322 * Stuff for the rmtcall service
326 typedef struct encap_parms
{
332 xdr_encap_parms(xdrs
, epp
)
334 struct encap_parms
*epp
;
337 return (xdr_bytes(xdrs
, &(epp
->args
), &(epp
->arglen
), ARGSIZE
));
340 typedef struct rmtcallargs
{
345 struct encap_parms rmt_args
;
349 xdr_rmtcall_args(xdrs
, cap
)
351 register struct rmtcallargs
*cap
;
354 /* does not get a port number */
355 if (xdr_u_long(xdrs
, &(cap
->rmt_prog
)) &&
356 xdr_u_long(xdrs
, &(cap
->rmt_vers
)) &&
357 xdr_u_long(xdrs
, &(cap
->rmt_proc
))) {
358 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
364 xdr_rmtcall_result(xdrs
, cap
)
366 register struct rmtcallargs
*cap
;
368 if (xdr_u_long(xdrs
, &(cap
->rmt_port
)))
369 return (xdr_encap_parms(xdrs
, &(cap
->rmt_args
)));
374 * only worries about the struct encap_parms part of struct rmtcallargs.
375 * The arglen must already be set!!
378 xdr_opaque_parms(xdrs
, cap
)
380 struct rmtcallargs
*cap
;
383 return (xdr_opaque(xdrs
, cap
->rmt_args
.args
, cap
->rmt_args
.arglen
));
387 * This routine finds and sets the length of incoming opaque paraters
388 * and then calls xdr_opaque_parms.
391 xdr_len_opaque_parms(xdrs
, cap
)
393 struct rmtcallargs
*cap
;
395 register u_int beginpos
, lowpos
, highpos
, currpos
, pos
;
397 beginpos
= lowpos
= pos
= xdr_getpos(xdrs
);
398 highpos
= lowpos
+ ARGSIZE
;
399 while ((int)(highpos
- lowpos
) >= 0) {
400 currpos
= (lowpos
+ highpos
) / 2;
401 if (xdr_setpos(xdrs
, currpos
)) {
403 lowpos
= currpos
+ 1;
405 highpos
= currpos
- 1;
408 xdr_setpos(xdrs
, beginpos
);
409 cap
->rmt_args
.arglen
= pos
- beginpos
;
410 return (xdr_opaque_parms(xdrs
, cap
));
414 * Call a remote procedure service
415 * This procedure is very quiet when things go wrong.
416 * The proc is written to support broadcast rpc. In the broadcast case,
417 * a machine should shut-up instead of complain, less the requestor be
418 * overrun with complaints at the expense of not hearing a valid reply ...
420 * This now forks so that the program & process that it calls can call
421 * back to the portmapper.
425 struct svc_req
*rqstp
;
428 struct rmtcallargs a
;
429 struct pmaplist
*pml
;
431 struct sockaddr_in me
;
432 int pid
, socket
= -1;
434 struct authunix_parms
*au
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
435 struct timeval timeout
;
440 a
.rmt_args
.args
= buf
;
441 if (!svc_getargs(xprt
, xdr_rmtcall_args
, &a
))
443 if ((pml
= find_service(a
.rmt_prog
, a
.rmt_vers
, IPPROTO_UDP
)) == NULL
)
446 * fork a child to do the work. Parent immediately returns.
447 * Child exits upon completion.
449 if ((pid
= fork()) != 0) {
450 if (debugging
&& (pid
< 0)) {
451 fprintf(stderr
, _("portmap CALLIT: cannot fork.\n"));
455 port
= pml
->pml_map
.pm_port
;
457 me
.sin_port
= htons(port
);
458 client
= clntudp_create(&me
, a
.rmt_prog
, a
.rmt_vers
, timeout
, &socket
);
459 if (client
!= (CLIENT
*)NULL
) {
460 if (rqstp
->rq_cred
.oa_flavor
== AUTH_UNIX
) {
461 client
->cl_auth
= authunix_create(au
->aup_machname
,
462 au
->aup_uid
, au
->aup_gid
, au
->aup_len
, au
->aup_gids
);
464 a
.rmt_port
= (u_long
)port
;
465 if (clnt_call(client
, a
.rmt_proc
, xdr_opaque_parms
, &a
,
466 xdr_len_opaque_parms
, &a
, timeout
) == RPC_SUCCESS
) {
467 svc_sendreply(xprt
, xdr_rmtcall_result
, &a
);
469 AUTH_DESTROY(client
->cl_auth
);
470 clnt_destroy(client
);
472 /* (void)close(socket); clnt_destroy already closed it */
479 while (wait3(NULL
, WNOHANG
, NULL
) > 0);