Thu Nov 2 19:24:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / sunrpc / portmap.c
blobadfdef955ecdd62f7266296b1578570964e9a520
1 /* @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC */
2 #ifndef lint
3 static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
4 #endif
6 /*
7 * Copyright (c) 1984 by Sun Microsystems, Inc.
8 */
11 * portmap.c, Implements the program,version to port number mapping for
12 * rpc.
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.
40 * 2550 Garcia Avenue
41 * Mountain View, California 94043
44 #include <rpc/rpc.h>
45 #include <rpc/pmap_prot.h>
46 #include <stdio.h>
47 #include <netdb.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #include <sys/wait.h>
51 #include <sys/signal.h>
53 char *malloc();
54 int reg_service();
55 void reap();
56 struct pmaplist *pmaplist;
57 static int debugging = 0;
59 main()
61 SVCXPRT *xprt;
62 int sock, pid, t;
63 struct sockaddr_in addr;
64 int len = sizeof(struct sockaddr_in);
65 register struct pmaplist *pml;
67 #ifndef DEBUG
68 pid = fork();
69 if (pid < 0) {
70 perror("portmap: fork");
71 exit(1);
73 if (pid != 0)
74 exit(0);
75 for (t = 0; t < 20; t++)
76 close(t);
77 open("/", 0);
78 dup2(0, 1);
79 dup2(0, 2);
80 t = open("/dev/tty", 2);
81 if (t >= 0) {
82 ioctl(t, TIOCNOTTY, (char *)0);
83 close(t);
85 #endif
86 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
87 perror("portmap cannot create socket");
88 exit(1);
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");
96 exit(1);
99 if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
100 fprintf(stderr, "couldn't do udp_create\n");
101 exit(1);
103 /* make an entry for ourself */
104 pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
105 pml->pml_next = 0;
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;
110 pmaplist = pml;
112 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
113 perror("portmap cannot create socket");
114 exit(1);
116 if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
117 perror("portmap cannot bind");
118 exit(1);
120 if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
121 == (SVCXPRT *)NULL) {
122 fprintf(stderr, "couldn't do tcp_create\n");
123 exit(1);
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;
132 pmaplist = pml;
134 (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
136 (void)signal(SIGCHLD, reap);
137 svc_run();
138 fprintf(stderr, "run_svc returned unexpectedly\n");
139 abort();
142 static struct pmaplist *
143 find_service(prog, vers, prot)
144 u_long prog;
145 u_long vers;
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))
153 continue;
154 hit = pml;
155 if (pml->pml_map.pm_vers == vers)
156 break;
158 return (hit);
162 * 1 OK, 0 not
164 reg_service(rqstp, xprt)
165 struct svc_req *rqstp;
166 SVCXPRT *xprt;
168 struct pmap reg;
169 struct pmaplist *pml, *prevpml, *fnd;
170 int ans, port;
171 caddr_t t;
173 #ifdef DEBUG
174 fprintf(stderr, "server: about do a switch\n");
175 #endif
176 switch (rqstp->rq_proc) {
178 case PMAPPROC_NULL:
180 * Null proc call
182 if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
183 abort();
185 break;
187 case PMAPPROC_SET:
189 * Set a program,version to port mapping
191 if (!svc_getargs(xprt, xdr_pmap, &reg))
192 svcerr_decode(xprt);
193 else {
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) {
202 ans = 1;
203 goto done;
205 else {
206 ans = 0;
207 goto done;
209 } else {
211 * add to END of list
213 pml = (struct pmaplist *)
214 malloc((u_int)sizeof(struct pmaplist));
215 pml->pml_map = reg;
216 pml->pml_next = 0;
217 if (pmaplist == 0) {
218 pmaplist = pml;
219 } else {
220 for (fnd= pmaplist; fnd->pml_next != 0;
221 fnd = fnd->pml_next);
222 fnd->pml_next = pml;
224 ans = 1;
226 done:
227 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
228 debugging) {
229 fprintf(stderr, "svc_sendreply\n");
230 abort();
233 break;
235 case PMAPPROC_UNSET:
237 * Remove a program,version to port mapping.
239 if (!svc_getargs(xprt, xdr_pmap, &reg))
240 svcerr_decode(xprt);
241 else {
242 ans = 0;
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 */
247 prevpml = pml;
248 pml = pml->pml_next;
249 continue;
251 /* found it; pml moves forward, prevpml stays */
252 ans = 1;
253 t = (caddr_t)pml;
254 pml = pml->pml_next;
255 if (prevpml == NULL)
256 pmaplist = pml;
257 else
258 prevpml->pml_next = pml;
259 free(t);
261 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
262 debugging) {
263 fprintf(stderr, "svc_sendreply\n");
264 abort();
267 break;
269 case PMAPPROC_GETPORT:
271 * Lookup the mapping for a program,version and return its port
273 if (!svc_getargs(xprt, xdr_pmap, &reg))
274 svcerr_decode(xprt);
275 else {
276 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
277 if (fnd)
278 port = fnd->pml_map.pm_port;
279 else
280 port = 0;
281 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
282 debugging) {
283 fprintf(stderr, "svc_sendreply\n");
284 abort();
287 break;
289 case PMAPPROC_DUMP:
291 * Return the current set of mapped program,version
293 if (!svc_getargs(xprt, xdr_void, NULL))
294 svcerr_decode(xprt);
295 else {
296 if ((!svc_sendreply(xprt, xdr_pmaplist,
297 (caddr_t)&pmaplist)) && debugging) {
298 fprintf(stderr, "svc_sendreply\n");
299 abort();
302 break;
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.
312 callit(rqstp, xprt);
313 break;
315 default:
316 svcerr_noproc(xprt);
317 break;
323 * Stuff for the rmtcall service
325 #define ARGSIZE 9000
327 typedef struct encap_parms {
328 u_long arglen;
329 char *args;
332 static bool_t
333 xdr_encap_parms(xdrs, epp)
334 XDR *xdrs;
335 struct encap_parms *epp;
338 return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
341 typedef struct rmtcallargs {
342 u_long rmt_prog;
343 u_long rmt_vers;
344 u_long rmt_port;
345 u_long rmt_proc;
346 struct encap_parms rmt_args;
349 static bool_t
350 xdr_rmtcall_args(xdrs, cap)
351 register XDR *xdrs;
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)));
361 return (FALSE);
364 static bool_t
365 xdr_rmtcall_result(xdrs, cap)
366 register XDR *xdrs;
367 register struct rmtcallargs *cap;
369 if (xdr_u_long(xdrs, &(cap->rmt_port)))
370 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
371 return (FALSE);
375 * only worries about the struct encap_parms part of struct rmtcallargs.
376 * The arglen must already be set!!
378 static bool_t
379 xdr_opaque_parms(xdrs, cap)
380 XDR *xdrs;
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.
391 static bool_t
392 xdr_len_opaque_parms(xdrs, cap)
393 register XDR *xdrs;
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)) {
403 pos = currpos;
404 lowpos = currpos + 1;
405 } else {
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.
424 static
425 callit(rqstp, xprt)
426 struct svc_req *rqstp;
427 SVCXPRT *xprt;
429 struct rmtcallargs a;
430 struct pmaplist *pml;
431 u_short port;
432 struct sockaddr_in me;
433 int pid, socket = -1;
434 CLIENT *client;
435 struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
436 struct timeval timeout;
437 char buf[ARGSIZE];
439 timeout.tv_sec = 5;
440 timeout.tv_usec = 0;
441 a.rmt_args.args = buf;
442 if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
443 return;
444 if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
445 return;
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");
454 return;
456 port = pml->pml_map.pm_port;
457 get_myaddress(&me);
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);
473 (void)close(socket);
474 exit(0);
477 void
478 reap()
480 while (wait3(NULL, WNOHANG, NULL) > 0);