xref: /freebsd/usr.sbin/rpcbind/check_bound.c (revision fd45b686f9d92f583366c75b22c04c7ee49709c0)
1 /*	$NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2009, Sun Microsystems, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * - Redistributions of source code must retain the above copyright notice,
12  *   this list of conditions and the following disclaimer.
13  * - Redistributions in binary form must reproduce the above copyright notice,
14  *   this list of conditions and the following disclaimer in the documentation
15  *   and/or other materials provided with the distribution.
16  * - Neither the name of Sun Microsystems, Inc. nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34  */
35 
36 /*
37  * check_bound.c
38  * Checks to see whether the program is still bound to the
39  * claimed address and returns the universal merged address
40  *
41  */
42 
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <rpc/rpc.h>
46 #include <rpc/svc_dg.h>
47 #include <netconfig.h>
48 #include <syslog.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 
53 #include "rpcbind.h"
54 
55 struct fdlist {
56 	int fd;
57 	struct netconfig *nconf;
58 	struct fdlist *next;
59 	int check_binding;
60 };
61 
62 static struct fdlist *fdhead;	/* Link list of the check fd's */
63 static struct fdlist *fdtail;
64 static char *nullstring = "";
65 
66 static bool_t check_bound(struct fdlist *, char *uaddr);
67 
68 /*
69  * Returns 1 if the given address is bound for the given addr & transport
70  * For all error cases, we assume that the address is bound
71  * Returns 0 for success.
72  */
73 static bool_t
74 check_bound(struct fdlist *fdl, char *uaddr)
75 {
76 	int fd;
77 	struct netbuf *na;
78 	int ans;
79 
80 	if (fdl->check_binding == FALSE)
81 		return (TRUE);
82 
83 	na = uaddr2taddr(fdl->nconf, uaddr);
84 	if (!na)
85 		return (TRUE); /* punt, should never happen */
86 
87 	fd = __rpc_nconf2fd(fdl->nconf);
88 	if (fd < 0) {
89 		free(na->buf);
90 		free(na);
91 		return (TRUE);
92 	}
93 
94 	ans = bind(fd, (struct sockaddr *)na->buf, na->len);
95 
96 	close(fd);
97 	free(na->buf);
98 	free(na);
99 
100 	return (ans == 0 ? FALSE : TRUE);
101 }
102 
103 int
104 add_bndlist(struct netconfig *nconf, struct netbuf *baddr __unused)
105 {
106 	struct fdlist *fdl;
107 	struct netconfig *newnconf;
108 
109 	newnconf = getnetconfigent(nconf->nc_netid);
110 	if (newnconf == NULL)
111 		return (-1);
112 	fdl = malloc(sizeof (struct fdlist));
113 	if (fdl == NULL) {
114 		freenetconfigent(newnconf);
115 		syslog(LOG_ERR, "no memory!");
116 		return (-1);
117 	}
118 	fdl->nconf = newnconf;
119 	fdl->next = NULL;
120 	if (fdhead == NULL) {
121 		fdhead = fdl;
122 		fdtail = fdl;
123 	} else {
124 		fdtail->next = fdl;
125 		fdtail = fdl;
126 	}
127 	/* XXX no bound checking for now */
128 	fdl->check_binding = FALSE;
129 
130 	return 0;
131 }
132 
133 bool_t
134 is_bound(char *netid, char *uaddr)
135 {
136 	struct fdlist *fdl;
137 
138 	for (fdl = fdhead; fdl; fdl = fdl->next)
139 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
140 			break;
141 	if (fdl == NULL)
142 		return (TRUE);
143 	return (check_bound(fdl, uaddr));
144 }
145 
146 /*
147  * Returns NULL if there was some system error.
148  * Returns "" if the address was not bound, i.e the server crashed.
149  * Returns the merged address otherwise.
150  */
151 char *
152 mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
153 {
154 	struct fdlist *fdl;
155 	struct netbuf *callee;
156 	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
157 
158 	for (fdl = fdhead; fdl; fdl = fdl->next)
159 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
160 			break;
161 	if (fdl == NULL)
162 		return (NULL);
163 	if (check_bound(fdl, uaddr) == FALSE)
164 		/* that server died */
165 		return (nullstring);
166 	/*
167 	 * Try to determine the local address on which the client contacted us,
168 	 * so we can send a reply from the same address.  If it's unknown, then
169 	 * try to determine which address the client used, and pick a nearby
170 	 * local address.
171 	 *
172 	 * If saddr is not NULL, the remote client may have included the
173 	 * address by which it contacted us.  Use that for the "client" uaddr,
174 	 * otherwise use the info from the SVCXPRT.
175 	 */
176 	callee = svc_getrpccallee(xprt);
177 	if (callee != NULL && callee->buf != NULL) {
178 		c_uaddr = taddr2uaddr(fdl->nconf, callee);
179 		allocated_uaddr = c_uaddr;
180 	} else if (saddr != NULL) {
181 		c_uaddr = saddr;
182 	} else {
183 		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
184 		allocated_uaddr = c_uaddr;
185 	}
186 	if (c_uaddr == NULL) {
187 		syslog(LOG_ERR, "taddr2uaddr failed for %s",
188 			fdl->nconf->nc_netid);
189 		return (NULL);
190 	}
191 
192 #ifdef ND_DEBUG
193 	if (debugging) {
194 		if (saddr == NULL) {
195 			fprintf(stderr, "mergeaddr: client uaddr = %s\n",
196 			    c_uaddr);
197 		} else {
198 			fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
199 			    c_uaddr);
200 		}
201 	}
202 #endif
203 	s_uaddr = uaddr;
204 	/*
205 	 * This is all we should need for IP 4 and 6
206 	 */
207 	m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
208 #ifdef ND_DEBUG
209 	if (debugging)
210 		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
211 				uaddr, m_uaddr);
212 #endif
213 	free(allocated_uaddr);
214 	return (m_uaddr);
215 }
216 
217 /*
218  * Returns a netconf structure from its internal list.  This
219  * structure should not be freed.
220  */
221 struct netconfig *
222 rpcbind_get_conf(const char *netid)
223 {
224 	struct fdlist *fdl;
225 
226 	for (fdl = fdhead; fdl; fdl = fdl->next)
227 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
228 			break;
229 	if (fdl == NULL)
230 		return (NULL);
231 	return (fdl->nconf);
232 }
233