xref: /dragonfly/usr.sbin/rpcbind/check_bound.c (revision 479ab7f0)
1 /*
2  * Copyright (c) 2009, Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13  *   contributors may be used to endorse or promote products derived
14  *   from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * @(#)check_bound.c	1.15	93/07/05 SMI; 1.11 89/04/21 Copyr 1989 Sun Micro
29  * $NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $
30  * $FreeBSD: src/usr.sbin/rpcbind/check_bound.c,v 1.5 2007/11/07 10:53:39 kevlo Exp $
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 univeral merged address
40  *
41  */
42 
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <rpc/rpc.h>
46 #include <stdio.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 	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
156 
157 	for (fdl = fdhead; fdl; fdl = fdl->next)
158 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
159 			break;
160 	if (fdl == NULL)
161 		return (NULL);
162 	if (check_bound(fdl, uaddr) == FALSE)
163 		/* that server died */
164 		return (nullstring);
165 	/*
166 	 * If saddr is not NULL, the remote client may have included the
167 	 * address by which it contacted us.  Use that for the "client" uaddr,
168 	 * otherwise use the info from the SVCXPRT.
169 	 */
170 	if (saddr != NULL) {
171 		c_uaddr = saddr;
172 	} else {
173 		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
174 		if (c_uaddr == NULL) {
175 			syslog(LOG_ERR, "taddr2uaddr failed for %s",
176 				fdl->nconf->nc_netid);
177 			return (NULL);
178 		}
179 		allocated_uaddr = c_uaddr;
180 	}
181 
182 #ifdef ND_DEBUG
183 	if (debugging) {
184 		if (saddr == NULL) {
185 			fprintf(stderr, "mergeaddr: client uaddr = %s\n",
186 			    c_uaddr);
187 		} else {
188 			fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
189 			    c_uaddr);
190 		}
191 	}
192 #endif
193 	s_uaddr = uaddr;
194 	/*
195 	 * This is all we should need for IP 4 and 6
196 	 */
197 	m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
198 #ifdef ND_DEBUG
199 	if (debugging)
200 		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
201 				uaddr, m_uaddr);
202 #endif
203 	if (allocated_uaddr != NULL)
204 		free(allocated_uaddr);
205 	return (m_uaddr);
206 }
207 
208 /*
209  * Returns a netconf structure from its internal list.  This
210  * structure should not be freed.
211  */
212 struct netconfig *
213 rpcbind_get_conf(char *netid)
214 {
215 	struct fdlist *fdl;
216 
217 	for (fdl = fdhead; fdl; fdl = fdl->next)
218 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
219 			break;
220 	if (fdl == NULL)
221 		return (NULL);
222 	return (fdl->nconf);
223 }
224