Commit | Line | Data |
---|---|---|
95f51977 C |
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 | } |