BSD 4_3_Tahoe release
[unix-history] / usr / src / new / sunrpc / portmap.c
CommitLineData
95f51977
C
1#ifndef lint
2static 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
51char *malloc();
52int reg_service();
53static int debugging = 0;
54
55main()
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
118struct pmaplist *pmaplist;
119
120static struct pmaplist *
121find_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 */
142reg_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, &reg))
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, &reg))
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, &reg))
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
299typedef struct encap_parms {
300 u_long arglen;
301 char *args;
302};
303
304static bool_t
305xdr_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
313typedef 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
321static bool_t
322xdr_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
336static bool_t
337xdr_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 */
350static bool_t
351xdr_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 */
363static bool_t
364xdr_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 */
393static
394callit(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}