Merge up from branch.
[shibboleth/cpp-sp.git] / oncrpc / portmap.c
1 /*********************************************************************
2  * RPC for the Windows NT Operating System
3  * 1993 by Martin F. Gergeleit
4  * Users may use, copy or modify Sun RPC for the Windows NT Operating 
5  * System according to the Sun copyright below.
6  *
7  * RPC for the Windows NT Operating System COMES WITH ABSOLUTELY NO 
8  * WARRANTY, NOR WILL I BE LIABLE FOR ANY DAMAGES INCURRED FROM THE 
9  * USE OF. USE ENTIRELY AT YOUR OWN RISK!!!
10  *********************************************************************/
11
12 #if !defined(lint) && !defined(_NOIDENT)
13 static char rcsid[] = "@(#)$RCSfile$ $Revision$ (OSF) $Date$";
14 #endif
15 #ifndef lint
16 static  char sccsid[] = "@(#)portmap.c 1.2 85/03/13 Copyr 1984 Sun Micro";
17 #endif
18
19 /*
20  * Copyright (c) 1984 by Sun Microsystems, Inc.
21  */
22
23 /*
24  * portmap.c, Implements the program,version to port number mapping for
25  * rpc.
26  * Modified to debug based on global var. "debug" so that you can twiddle
27  * it with adb and to use syslog for errors. rick macklem
28  */
29
30 /*
31  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
32  * unrestricted use provided that this legend is included on all tape
33  * media and as a part of the software program in whole or part.  Users
34  * may copy or modify Sun RPC without charge, but are not authorized
35  * to license or distribute it to anyone else except as part of a product or
36  * program developed by the user.
37  * 
38  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
39  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
41  * 
42  * Sun RPC is provided with no support and without any obligation on the
43  * part of Sun Microsystems, Inc. to assist in its use, correction,
44  * modification or enhancement.
45  * 
46  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
47  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
48  * OR ANY PART THEREOF.
49  * 
50  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
51  * or profits or other special, indirect and consequential damages, even if
52  * Sun has been advised of the possibility of such damages.
53  * 
54  * Sun Microsystems, Inc.
55  * 2550 Garcia Avenue
56  * Mountain View, California  94043
57  */
58
59 #include <rpc/rpc.h>
60 #include <rpc/pmap_prot.h>
61 #include <stdio.h>
62
63 int reg_service();
64 static callit();
65
66 #ifdef DEBUG
67 #define syslog(e, s)    fprintf(stderr, (s))
68 static int debug = 1;
69 #else
70 static int debug = 0;
71 #endif
72
73
74 main()
75 {
76         SVCXPRT *xprt;
77         int sock, pid, t;
78         struct sockaddr_in addr;
79         int len = sizeof(struct sockaddr_in);
80
81 #if 0
82         if (!debug) {
83                 pid = daemon(0,0);      /* from libutil */
84                 if (pid < 0) {
85                         perror("portmap: fork");
86                         exit(1);
87                 }
88         }
89
90         openlog("portmap:", LOG_PID, LOG_DAEMON);
91 #endif
92
93         if (rpc_nt_init() != 0) {
94                 fprintf(stderr, "cannot init WinSock\n");
95                 exit(1);
96         }
97         
98
99         if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
100                 fprintf(stderr, "cannot create socket\n");
101                 exit(1);
102         }
103
104         addr.sin_addr.s_addr = 0;
105         addr.sin_family = AF_INET;
106         addr.sin_port = htons(PMAPPORT);
107         if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
108                 fprintf(stderr, "cannot bind\n");
109                 exit(1);
110         }
111
112         if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
113                 fprintf(stderr, "couldn't do udp_create\n");
114                 exit(1);
115         }
116
117         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
118                 fprintf(stderr, "cannot create socket\n");
119                 exit(1);
120         }
121         if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
122                 fprintf(stderr, "cannot bind\n");
123                 exit(1);
124         }
125         if ((xprt = svctcp_create(sock, 0, 0)) == (SVCXPRT *)NULL) {
126                 fprintf(stderr, "couldn't do tcp_create\n");
127                 exit(1);
128         }
129
130         (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
131         svc_run();
132         fprintf(stderr, "run_svc returned unexpectedly\n");
133
134         rpc_nt_exit();
135
136         abort();
137 }
138
139 struct pmaplist *pmaplist;
140
141 static struct pmaplist *
142 find_service(prog, vers, prot)
143         u_long prog;
144         u_long vers;
145 {
146         register struct pmaplist *hit = NULL;
147         register struct pmaplist *pml;
148
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))
152                         continue;
153                 hit = pml;
154                 if (pml->pml_map.pm_vers == vers)
155                     break;
156         }
157
158         return (hit);
159 }
160
161 /* 
162  * 1 OK, 0 not
163  */
164 reg_service(rqstp, xprt)
165         struct svc_req *rqstp;
166         SVCXPRT *xprt;
167 {
168         struct pmap reg;
169         struct pmaplist *pml, *prevpml, *fnd;
170         int ans, port;
171         caddr_t t;
172         
173         if (debug)
174                 fprintf(stderr, "server: about do a switch\n");
175         switch (rqstp->rq_proc) {
176
177         case PMAPPROC_NULL:
178                 /*
179                  * Null proc call
180                  */
181                 if ((!svc_sendreply(xprt, xdr_void, NULL)) && debug) {
182                         abort();
183                 }
184                 break;
185
186         case PMAPPROC_SET:
187                 /*
188                  * Set a program,version to port mapping
189                  */
190                 if (!svc_getargs(xprt, xdr_pmap, &reg))
191                         svcerr_decode(xprt);
192                 else {
193                         /*
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
197                          */
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) {
201                                         ans = 1;
202                                         goto done;
203                                 }
204                                 else {
205                                         ans = 0;
206                                         goto done;
207                                 }
208                         } else {
209                                 /* 
210                                  * add to list
211                                  */
212                                 pml = (struct pmaplist *)
213                                     malloc((u_int)sizeof(struct pmaplist));
214                                 pml->pml_map = reg;
215                                 pml->pml_next = pmaplist;
216                                 pmaplist = pml;
217                                 ans = 1;
218                         }
219                 done:
220                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
221                             debug) {
222                                 fprintf(stderr, "svc_sendreply\n");
223                                 abort();
224                         }
225                 }
226                 break;
227
228         case PMAPPROC_UNSET:
229                 /*
230                  * Remove a program,version to port mapping.
231                  */
232                 if (!svc_getargs(xprt, xdr_pmap, &reg))
233                         svcerr_decode(xprt);
234                 else {
235                         ans = 0;
236                         for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
237                                 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
238                                         (pml->pml_map.pm_vers != reg.pm_vers)) {
239                                         /* both pml & prevpml move forwards */
240                                         prevpml = pml;
241                                         pml = pml->pml_next;
242                                         continue;
243                                 }
244                                 /* found it; pml moves forward, prevpml stays */
245                                 ans = 1;
246                                 t = (caddr_t)pml;
247                                 pml = pml->pml_next;
248                                 if (prevpml == NULL)
249                                         pmaplist = pml;
250                                 else
251                                         prevpml->pml_next = pml;
252                                 free(t);
253                         }
254                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
255                             debug) {
256                                 fprintf(stderr, "svc_sendreply\n");
257                                 abort();
258                         }
259                 }
260                 break;
261
262         case PMAPPROC_GETPORT:
263                 /*
264                  * Lookup the mapping for a program,version and return its port
265                  */
266                 if (!svc_getargs(xprt, xdr_pmap, &reg))
267                         svcerr_decode(xprt);
268                 else {
269                         fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
270                         if (fnd)
271                                 port = fnd->pml_map.pm_port;
272                         else
273                                 port = 0;
274                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
275                             debug) {
276                                 fprintf(stderr, "svc_sendreply\n");
277                                 abort();
278                         }
279                 }
280                 break;
281
282         case PMAPPROC_DUMP:
283                 /*
284                  * Return the current set of mapped program,version
285                  */
286                 if (!svc_getargs(xprt, xdr_void, NULL))
287                         svcerr_decode(xprt);
288                 else {
289                         if ((!svc_sendreply(xprt, xdr_pmaplist,
290                             (caddr_t)&pmaplist)) && debug) {
291                                 fprintf(stderr, "svc_sendreply\n");
292                                 abort();
293                         }
294                 }
295                 break;
296
297         case PMAPPROC_CALLIT:
298                 /*
299                  * Calls a procedure on the local machine.  If the requested
300                  * procedure is not registered this procedure does not return
301                  * error information!!
302                  * This procedure is only supported on rpc/udp and calls via 
303                  * rpc/udp.  It passes null authentication parameters.
304                  */
305                 callit(rqstp, xprt);
306                 break;
307
308         default:
309                 svcerr_noproc(xprt);
310                 break;
311         }
312 }
313
314
315 /*
316  * Stuff for the rmtcall service
317  */
318 #define ARGSIZE 9000
319
320 typedef struct encap_parms {
321         u_long arglen;
322         char *args;
323 } encap_parms_t;
324
325 static bool_t
326 xdr_encap_parms(xdrs, epp)
327         XDR *xdrs;
328         struct encap_parms *epp;
329 {
330
331         return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
332 }
333
334 typedef struct rmtcallargs {
335         u_long  rmt_prog;
336         u_long  rmt_vers;
337         u_long  rmt_port;
338         u_long  rmt_proc;
339         struct encap_parms rmt_args;
340 } rmtcallargs_t;
341
342 static bool_t
343 xdr_rmtcall_args(xdrs, cap)
344         register XDR *xdrs;
345         register struct rmtcallargs *cap;
346 {
347
348         /* does not get a port number */
349         if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
350             xdr_u_long(xdrs, &(cap->rmt_vers)) &&
351             xdr_u_long(xdrs, &(cap->rmt_proc))) {
352                 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
353         }
354         return (FALSE);
355 }
356
357 static bool_t
358 xdr_rmtcall_result(xdrs, cap)
359         register XDR *xdrs;
360         register struct rmtcallargs *cap;
361 {
362         if (xdr_u_long(xdrs, &(cap->rmt_port)))
363                 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
364         return (FALSE);
365 }
366
367 /*
368  * only worries about the struct encap_parms part of struct rmtcallargs.
369  * The arglen must already be set!!
370  */
371 static bool_t
372 xdr_opaque_parms(xdrs, cap)
373         XDR *xdrs;
374         struct rmtcallargs *cap;
375 {
376
377         return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
378 }
379
380 /*
381  * This routine finds and sets the length of incoming opaque paraters
382  * and then calls xdr_opaque_parms.
383  */
384 static bool_t
385 xdr_len_opaque_parms(xdrs, cap)
386         register XDR *xdrs;
387         struct rmtcallargs *cap;
388 {
389         register u_int beginpos, lowpos, highpos, currpos, pos;
390
391         beginpos = lowpos = pos = xdr_getpos(xdrs);
392         highpos = lowpos + ARGSIZE;
393         while ((int)(highpos - lowpos) >= 0) {
394                 currpos = (lowpos + highpos) / 2;
395                 if (xdr_setpos(xdrs, currpos)) {
396                         pos = currpos;
397                         lowpos = currpos + 1;
398                 } else {
399                         highpos = currpos - 1;
400                 }
401         }
402         xdr_setpos(xdrs, beginpos);
403         cap->rmt_args.arglen = pos - beginpos;
404         return (xdr_opaque_parms(xdrs, cap));
405 }
406
407 /*
408  * Call a remote procedure service
409  * This procedure is very quiet when things go wrong.
410  * The proc is written to support broadcast rpc.  In the broadcast case,
411  * a machine should shut-up instead of complain, less the requestor be
412  * overrun with complaints at the expense of not hearing a valid reply ...
413  */
414 static
415 callit(rqstp, xprt)
416         struct svc_req *rqstp;
417         SVCXPRT *xprt;
418 {
419         char buf[2000];
420         struct rmtcallargs a;
421         struct pmaplist *pml;
422         u_short port;
423         struct sockaddr_in me;
424         int socket = -1;
425         CLIENT *client;
426         struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
427         struct timeval timeout;
428
429         timeout.tv_sec = 5;
430         timeout.tv_usec = 0;
431         a.rmt_args.args = buf;
432         if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
433             return;
434         if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
435             return;
436         port = pml->pml_map.pm_port;
437         get_myaddress(&me);
438         me.sin_port = htons(port);
439         client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
440         if (client != (CLIENT *)NULL) {
441                 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
442                         client->cl_auth = authunix_create(au->aup_machname,
443                            au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
444                 }
445                 a.rmt_port = (u_long)port;
446                 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
447                     xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
448                         svc_sendreply(xprt, xdr_rmtcall_result, &a);
449                 }
450                 AUTH_DESTROY(client->cl_auth);
451                 clnt_destroy(client);
452         }
453         (void)closesocket(socket);
454 }