4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
31 * The server procedure for the version 4 rpcbind.
36 #include <sys/types.h>
40 #include <netconfig.h>
47 static void free_rpcb_entry_list(rpcb_entry_list_ptr
);
48 static bool_t
xdr_rpcb_entry_list_ptr_wrap(XDR
*, rpcb_entry_list_ptr
*);
49 static bool_t
rpcbproc_getaddrlist(rpcb
*, rpcb_entry_list_ptr
*,
53 * Called by svc_getreqset. There is a separate server handle for
54 * every transport that it waits on.
57 rpcb_service_4(struct svc_req
*rqstp
, SVCXPRT
*transp
)
60 rpcb rpcbproc_set_4_arg
;
61 rpcb rpcbproc_unset_4_arg
;
62 rpcb rpcbproc_getaddr_4_arg
;
63 char *rpcbproc_uaddr2taddr_4_arg
;
64 struct netbuf rpcbproc_taddr2uaddr_4_arg
;
65 rpcb rpcbproc_getversaddr_4_arg
;
66 rpcb rpcbproc_getaddrlist_4_arg
;
69 bool_t rpcbproc_set_4_res
;
70 bool_t rpcbproc_unset_4_res
;
71 char *rpcbproc_getaddr_4_res
;
72 rpcblist_ptr
*rpcbproc_dump_4_res
;
73 ulong_t rpcbproc_gettime_4_res
;
74 struct netbuf rpcbproc_uaddr2taddr_4_res
;
75 char *rpcbproc_taddr2uaddr_4_res
;
76 char *rpcbproc_getversaddr_4_res
;
77 rpcb_entry_list_ptr rpcbproc_getaddrlist_4_res
;
78 rpcb_stat_byvers
*rpcbproc_getstat_4_res
;
81 xdrproc_t xdr_argument
, xdr_result
;
84 rpcbs_procinfo(RPCBVERS_4_STAT
, rqstp
->rq_proc
);
86 RPCB_CHECK(transp
, rqstp
->rq_proc
);
88 switch (rqstp
->rq_proc
) {
93 (void) svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
);
98 * Check to see whether the message came from
99 * loopback transports (for security reasons)
101 if (strcasecmp(transp
->xp_netid
, loopback_dg
) &&
102 strcasecmp(transp
->xp_netid
, loopback_vc
) &&
103 strcasecmp(transp
->xp_netid
, loopback_vc_ord
)) {
104 syslog(LOG_ERR
, "non-local attempt to set");
105 svcerr_weakauth(transp
);
108 xdr_argument
= xdr_rpcb
;
109 xdr_result
= xdr_bool
;
110 local
= (bool_t (*)()) rpcbproc_set_com
;
115 * Check to see whether the message came from
116 * loopback transports (for security reasons)
118 if (strcasecmp(transp
->xp_netid
, loopback_dg
) &&
119 strcasecmp(transp
->xp_netid
, loopback_vc
) &&
120 strcasecmp(transp
->xp_netid
, loopback_vc_ord
)) {
121 syslog(LOG_ERR
, "non-local attempt to unset");
122 svcerr_weakauth(transp
);
125 xdr_argument
= xdr_rpcb
;
126 xdr_result
= xdr_bool
;
127 local
= (bool_t (*)()) rpcbproc_unset_com
;
130 case RPCBPROC_GETADDR
:
131 xdr_argument
= xdr_rpcb
;
132 xdr_result
= xdr_wrapstring
;
133 local
= (bool_t (*)()) rpcbproc_getaddr_com
;
137 xdr_argument
= xdr_void
;
138 xdr_result
= xdr_rpcblist_ptr_ptr
;
139 local
= (bool_t (*)()) rpcbproc_dump_com
;
143 rpcbproc_callit_com(rqstp
, transp
, rqstp
->rq_proc
, RPCBVERS4
);
146 case RPCBPROC_GETTIME
:
147 xdr_argument
= xdr_void
;
148 xdr_result
= xdr_u_long
;
149 local
= (bool_t (*)()) rpcbproc_gettime_com
;
152 case RPCBPROC_UADDR2TADDR
:
153 xdr_argument
= xdr_wrapstring
;
154 xdr_result
= xdr_netbuf
;
155 local
= (bool_t (*)()) rpcbproc_uaddr2taddr_com
;
158 case RPCBPROC_TADDR2UADDR
:
159 xdr_argument
= xdr_netbuf
;
160 xdr_result
= xdr_wrapstring
;
161 local
= (bool_t (*)()) rpcbproc_taddr2uaddr_com
;
164 case RPCBPROC_GETVERSADDR
:
165 xdr_argument
= xdr_rpcb
;
166 xdr_result
= xdr_wrapstring
;
167 local
= (bool_t (*)()) rpcbproc_getaddr_com
;
170 case RPCBPROC_INDIRECT
:
171 rpcbproc_callit_com(rqstp
, transp
, rqstp
->rq_proc
, RPCBVERS4
);
174 case RPCBPROC_GETADDRLIST
:
175 xdr_argument
= xdr_rpcb
;
176 xdr_result
= xdr_rpcb_entry_list_ptr_wrap
;
177 local
= (bool_t (*)()) rpcbproc_getaddrlist
;
180 case RPCBPROC_GETSTAT
:
181 xdr_argument
= xdr_void
;
182 xdr_result
= xdr_rpcb_stat_byvers_ptr
;
183 local
= (bool_t (*)()) rpcbproc_getstat
;
187 svcerr_noproc(transp
);
190 (void) memset((char *)&argument
, 0, sizeof (argument
));
191 if (!svc_getargs(transp
, xdr_argument
, (char *)&argument
)) {
192 svcerr_decode(transp
);
194 (void) fprintf(stderr
, "rpcbind: could not decode\n");
197 retval
= (*local
)(&argument
, &result
, rqstp
, RPCBVERS4
);
198 if (retval
> 0 && !svc_sendreply(transp
, xdr_result
, (char *)&result
)) {
199 svcerr_systemerr(transp
);
201 (void) fprintf(stderr
, "rpcbind: svc_sendreply\n");
207 if (!svc_freeargs(transp
, xdr_argument
, (char *)&argument
)) {
209 (void) fprintf(stderr
, "unable to free arguments\n");
216 xdr_free(xdr_result
, (char *)&result
);
220 * Lookup the mapping for a program, version and return the
221 * addresses for all transports in the current transport family.
222 * We return a merged address.
225 rpcbproc_getaddrlist(rpcb
*regp
, rpcb_entry_list_ptr
*result
,
226 struct svc_req
*rqstp
)
228 rpcb_entry_list_ptr rlist
= *result
= NULL
;
229 rpcblist_ptr rbl
, next
, prev
;
230 rpcb_entry_list_ptr rp
, tail
= NULL
;
233 struct netconfig
*nconf
;
234 struct netconfig
*reg_nconf
;
235 char *saddr
, *maddr
= NULL
;
236 struct netconfig
*trans_conf
; /* transport netconfig */
237 SVCXPRT
*transp
= rqstp
->rq_xprt
;
240 * Deal with a possible window during which we could return an IPv6
241 * address when the caller wanted IPv4. See the comments in
242 * rpcbproc_getaddr_com() for more details.
244 trans_conf
= rpcbind_get_conf(transp
->xp_netid
);
245 if (strcmp(trans_conf
->nc_protofmly
, NC_INET6
) == 0) {
246 struct sockaddr_in6
*rmtaddr
;
248 rmtaddr
= (struct sockaddr_in6
*)transp
->xp_rtaddr
.buf
;
249 if (IN6_IS_ADDR_V4MAPPED(&rmtaddr
->sin6_addr
)) {
251 "IPv4 GETADDRLIST request mapped "
252 "to IPv6: ignoring");
259 reg_nconf
= rpcbind_get_conf(transp
->xp_netid
);
260 if (reg_nconf
== NULL
)
262 if (*(regp
->r_addr
) != '\0') {
263 saddr
= regp
->r_addr
;
269 (void) rw_wrlock(&list_rbl_lock
);
270 for (rbl
= list_rbl
; rbl
!= NULL
; rbl
= next
) {
271 next
= rbl
->rpcb_next
;
272 if ((rbl
->rpcb_map
.r_prog
== prog
) &&
273 (rbl
->rpcb_map
.r_vers
== vers
)) {
274 nconf
= rpcbind_get_conf(rbl
->rpcb_map
.r_netid
);
276 (void) rw_unlock(&list_rbl_lock
);
279 if (strcmp(nconf
->nc_protofmly
, reg_nconf
->nc_protofmly
)
282 continue; /* not same proto family */
284 if ((maddr
= mergeaddr(transp
, rbl
->rpcb_map
.r_netid
,
285 rbl
->rpcb_map
.r_addr
, saddr
)) == NULL
) {
288 } else if (!maddr
[0]) {
290 * The server died, remove this rpcb_map element
291 * from the list and free it.
294 (void) rw_wrlock(&list_pml_lock
);
295 (void) del_pmaplist(&rbl
->rpcb_map
);
296 (void) rw_unlock(&list_pml_lock
);
298 (void) delete_rbl(rbl
);
303 prev
->rpcb_next
= next
;
309 rp
= (rpcb_entry_list_ptr
)
310 malloc((uint_t
)sizeof (rpcb_entry_list
));
312 (void) rw_unlock(&list_rbl_lock
);
315 a
= &rp
->rpcb_entry_map
;
317 a
->r_nc_netid
= nconf
->nc_netid
;
318 a
->r_nc_semantics
= nconf
->nc_semantics
;
319 a
->r_nc_protofmly
= nconf
->nc_protofmly
;
320 a
->r_nc_proto
= nconf
->nc_proto
;
321 rp
->rpcb_entry_next
= NULL
;
326 tail
->rpcb_entry_next
= rp
;
333 (void) rw_unlock(&list_rbl_lock
);
336 * XXX: getaddrlist info is also being stuffed into getaddr.
337 * Perhaps wrong, but better than it not getting counted at all.
339 rpcbs_getaddr(RPCBVERS_4_STAT
, prog
, vers
, transp
->xp_netid
, maddr
);
345 free_rpcb_entry_list(rlist
);
350 * Free only the allocated structure, rest is all a pointer to some
351 * other data somewhere else.
354 free_rpcb_entry_list(rpcb_entry_list_ptr rlist
)
356 while (rlist
!= NULL
) {
357 rpcb_entry_list_ptr tmp
= rlist
;
358 rlist
= rlist
->rpcb_entry_next
;
359 free(tmp
->rpcb_entry_map
.r_maddr
);
365 xdr_rpcb_entry_list_ptr_wrap(XDR
*xdrs
, rpcb_entry_list_ptr
*rp
)
367 if (xdrs
->x_op
== XDR_FREE
) {
368 free_rpcb_entry_list(*rp
);
372 return (xdr_rpcb_entry_list_ptr(xdrs
, rp
));