mptable - raise WARNS to 6
[dragonfly.git] / usr.sbin / rpcbind / pmap_svc.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  *
29  * @(#)pmap_svc.c       1.14    93/07/05 SMI; 1.23 89/04/05 Copyr 1984 Sun Micro
30  * $NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $
31  * $FreeBSD: src/usr.sbin/rpcbind/pmap_svc.c,v 1.5 2007/11/07 10:53:39 kevlo Exp $
32  */
33 /*
34  * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
35  */
36
37 /*
38  * pmap_svc.c
39  * The server procedure for the version 2 portmaper.
40  * All the portmapper related interface from the portmap side.
41  */
42
43 #ifdef PORTMAP
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <stdio.h>
47 #include <rpc/rpc.h>
48 #include <rpc/pmap_prot.h>
49 #include <rpc/rpcb_prot.h>
50 #ifdef RPCBIND_DEBUG
51 #include <stdlib.h>
52 #endif
53 #include "rpcbind.h"
54
55 static struct pmaplist  *find_service_pmap(rpcprog_t, rpcvers_t, rpcprot_t);
56 static bool_t           pmapproc_change(struct svc_req *, SVCXPRT *, u_long);
57 static bool_t           pmapproc_getport(struct svc_req *, SVCXPRT *);
58 static bool_t           pmapproc_dump(struct svc_req *, SVCXPRT *);
59
60 /*
61  * Called for all the version 2 inquiries.
62  */
63 void
64 pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
65 {
66         rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
67         switch (rqstp->rq_proc) {
68         case PMAPPROC_NULL:
69                 /*
70                  * Null proc call
71                  */
72 #ifdef RPCBIND_DEBUG
73                 if (debugging)
74                         fprintf(stderr, "PMAPPROC_NULL\n");
75 #endif
76                 check_access(xprt, rqstp->rq_proc, NULL, PMAPVERS);
77                 if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) &&
78                         debugging) {
79                         if (doabort) {
80                                 rpcbind_abort();
81                         }
82                 }
83                 break;
84
85         case PMAPPROC_SET:
86                 /*
87                  * Set a program, version to port mapping
88                  */
89                 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
90                 break;
91
92         case PMAPPROC_UNSET:
93                 /*
94                  * Remove a program, version to port mapping.
95                  */
96                 pmapproc_change(rqstp, xprt, rqstp->rq_proc);
97                 break;
98
99         case PMAPPROC_GETPORT:
100                 /*
101                  * Lookup the mapping for a program, version and return its
102                  * port number.
103                  */
104                 pmapproc_getport(rqstp, xprt);
105                 break;
106
107         case PMAPPROC_DUMP:
108                 /*
109                  * Return the current set of mapped program, version
110                  */
111 #ifdef RPCBIND_DEBUG
112                 if (debugging)
113                         fprintf(stderr, "PMAPPROC_DUMP\n");
114 #endif
115                 pmapproc_dump(rqstp, xprt);
116                 break;
117
118         case PMAPPROC_CALLIT:
119                 /*
120                  * Calls a procedure on the local machine. If the requested
121                  * procedure is not registered this procedure does not return
122                  * error information!!
123                  * This procedure is only supported on rpc/udp and calls via
124                  * rpc/udp. It passes null authentication parameters.
125                  */
126                 rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
127                 break;
128
129         default:
130                 svcerr_noproc(xprt);
131                 break;
132         }
133 }
134
135 /*
136  * returns the item with the given program, version number. If that version
137  * number is not found, it returns the item with that program number, so that
138  * the port number is now returned to the caller. The caller when makes a
139  * call to this program, version number, the call will fail and it will
140  * return with PROGVERS_MISMATCH. The user can then determine the highest
141  * and the lowest version number for this program using clnt_geterr() and
142  * use those program version numbers.
143  */
144 static struct pmaplist *
145 find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
146 {
147         struct pmaplist *hit = NULL;
148         struct pmaplist *pml;
149
150         for (pml = list_pml; 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;
157         }
158         return (hit);
159 }
160
161 static bool_t
162 pmapproc_change(struct svc_req *rqstp __unused, SVCXPRT *xprt, unsigned long op)
163 {
164         struct pmap reg;
165         RPCB rpcbreg;
166         long ans;
167         struct sockaddr_in *who;
168         uid_t uid;
169         char uidbuf[32];
170
171 #ifdef RPCBIND_DEBUG
172         if (debugging)
173                 fprintf(stderr, "%s request for (%lu, %lu) : ",
174                     op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET",
175                     reg.pm_prog, reg.pm_vers);
176 #endif
177
178         if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)&reg)) {
179                 svcerr_decode(xprt);
180                 return (FALSE);
181         }
182
183         if (!check_access(xprt, op, &reg, PMAPVERS)) {
184                 svcerr_weakauth(xprt);
185                 return FALSE;
186         }
187
188         who = svc_getcaller(xprt);
189
190         /*
191          * Can't use getpwnam here. We might end up calling ourselves
192          * and looping.
193          */
194         if (__rpc_get_local_uid(xprt, &uid) < 0)
195                 rpcbreg.r_owner = "unknown";
196         else if (uid == 0)
197                 rpcbreg.r_owner = "superuser";
198         else {
199                 /* r_owner will be strdup-ed later */
200                 snprintf(uidbuf, sizeof uidbuf, "%d", uid);
201                 rpcbreg.r_owner = uidbuf;
202         }
203
204         rpcbreg.r_prog = reg.pm_prog;
205         rpcbreg.r_vers = reg.pm_vers;
206
207         if (op == PMAPPROC_SET) {
208                 char buf[32];
209
210                 snprintf(buf, sizeof buf, "0.0.0.0.%d.%d",
211                     (int)((reg.pm_port >> 8) & 0xff),
212                     (int)(reg.pm_port & 0xff));
213                 rpcbreg.r_addr = buf;
214                 if (reg.pm_prot == IPPROTO_UDP) {
215                         rpcbreg.r_netid = udptrans;
216                 } else if (reg.pm_prot == IPPROTO_TCP) {
217                         rpcbreg.r_netid = tcptrans;
218                 } else {
219                         ans = FALSE;
220                         goto done_change;
221                 }
222                 ans = map_set(&rpcbreg, rpcbreg.r_owner);
223         } else if (op == PMAPPROC_UNSET) {
224                 bool_t ans1, ans2;
225
226                 rpcbreg.r_addr = NULL;
227                 rpcbreg.r_netid = tcptrans;
228                 ans1 = map_unset(&rpcbreg, rpcbreg.r_owner);
229                 rpcbreg.r_netid = udptrans;
230                 ans2 = map_unset(&rpcbreg, rpcbreg.r_owner);
231                 ans = ans1 || ans2;
232         } else {
233                 ans = FALSE;
234         }
235 done_change:
236         if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t) &ans)) &&
237             debugging) {
238                 fprintf(stderr, "portmap: svc_sendreply\n");
239                 if (doabort) {
240                         rpcbind_abort();
241                 }
242         }
243 #ifdef RPCBIND_DEBUG
244         if (debugging)
245                 fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
246 #endif
247         if (op == PMAPPROC_SET)
248                 rpcbs_set(RPCBVERS_2_STAT, ans);
249         else
250                 rpcbs_unset(RPCBVERS_2_STAT, ans);
251         return (TRUE);
252 }
253
254 /* ARGSUSED */
255 static bool_t
256 pmapproc_getport(struct svc_req *rqstp __unused, SVCXPRT *xprt)
257 {
258         struct pmap reg;
259         long lport;
260         int port = 0;
261         struct pmaplist *fnd;
262 #ifdef RPCBIND_DEBUG
263         char *uaddr;
264 #endif
265
266         if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)&reg)) {
267                 svcerr_decode(xprt);
268                 return (FALSE);
269         }
270
271         if (!check_access(xprt, PMAPPROC_GETPORT, &reg, PMAPVERS)) {
272                 svcerr_weakauth(xprt);
273                 return FALSE;
274         }
275
276 #ifdef RPCBIND_DEBUG
277         if (debugging) {
278                 uaddr =  taddr2uaddr(rpcbind_get_conf(xprt->xp_netid),
279                             svc_getrpccaller(xprt));
280                 fprintf(stderr, "PMAP_GETPORT req for (%lu, %lu, %s) from %s :",
281                         reg.pm_prog, reg.pm_vers,
282                         reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr);
283                 free(uaddr);
284         }
285 #endif
286         fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot);
287         if (fnd) {
288                 char serveuaddr[32], *ua;
289                 int h1, h2, h3, h4, p1, p2;
290                 char *netid;
291
292                 if (reg.pm_prot == IPPROTO_UDP) {
293                         ua = udp_uaddr;
294                         netid = udptrans;
295                 } else {
296                         ua = tcp_uaddr; /* To get the len */
297                         netid = tcptrans;
298                 }
299                 if (ua == NULL) {
300                         goto sendreply;
301                 }
302                 if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3,
303                                 &h4, &p1, &p2) == 6) {
304                         p1 = (fnd->pml_map.pm_port >> 8) & 0xff;
305                         p2 = (fnd->pml_map.pm_port) & 0xff;
306                         snprintf(serveuaddr, sizeof serveuaddr,
307                             "%d.%d.%d.%d.%d.%d", h1, h2, h3, h4, p1, p2);
308                         if (is_bound(netid, serveuaddr)) {
309                                 port = fnd->pml_map.pm_port;
310                         } else { /* this service is dead; delete it */
311                                 delete_prog(reg.pm_prog);
312                         }
313                 }
314         }
315 sendreply:
316         lport = port;
317         if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&lport)) &&
318                         debugging) {
319                 fprintf(stderr, "portmap: svc_sendreply\n");
320                 if (doabort) {
321                         rpcbind_abort();
322                 }
323         }
324 #ifdef RPCBIND_DEBUG
325         if (debugging)
326                 fprintf(stderr, "port = %d\n", port);
327 #endif
328         rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
329                 reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
330                 port ? udptrans : "");
331
332         return (TRUE);
333 }
334
335 /* ARGSUSED */
336 static bool_t
337 pmapproc_dump(struct svc_req *rqstp __unused, SVCXPRT *xprt)
338 {
339         if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
340                 svcerr_decode(xprt);
341                 return (FALSE);
342         }
343
344         if (!check_access(xprt, PMAPPROC_DUMP, NULL, PMAPVERS)) {
345                 svcerr_weakauth(xprt);
346                 return FALSE;
347         }
348
349         if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist_ptr,
350                         (caddr_t)&list_pml)) && debugging) {
351                 if (debugging)
352                         fprintf(stderr, "portmap: svc_sendreply\n");
353                 if (doabort) {
354                         rpcbind_abort();
355                 }
356         }
357         return (TRUE);
358 }
359
360 #endif /* PORTMAP */