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