dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rpcbind / check_bound.c
blob1841377194de9b07f363c80ef82aac05a1b4655e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
22 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
42 * check_bound.c
43 * Checks to see whether the program is still bound to the
44 * claimed address and returns the univeral merged address
48 #include <stdio.h>
49 #include <rpc/rpc.h>
50 #include <netconfig.h>
51 #include <netdir.h>
52 #include <sys/syslog.h>
53 #include <stdlib.h>
54 #include "rpcbind.h"
55 #include <string.h>
56 /* the following just to get my address */
57 #include <errno.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <thread.h>
61 #include <synch.h>
62 #include <syslog.h>
64 struct fdlist {
65 int fd;
66 mutex_t fd_lock; /* protects fd */
67 struct netconfig *nconf;
68 struct fdlist *next;
69 int check_binding;
72 static struct fdlist *fdhead; /* Link list of the check fd's */
73 static struct fdlist *fdtail;
74 static char *nullstring = "";
77 * Returns 1 if the given address is bound for the given addr & transport
78 * For all error cases, we assume that the address is bound
79 * Returns 0 for success.
81 * fdl: My FD list
82 * uaddr: the universal address
84 static bool_t
85 check_bound(struct fdlist *fdl, char *uaddr)
87 int fd;
88 struct netbuf *na;
89 struct t_bind taddr, *baddr;
90 int ans;
92 if (fdl->check_binding == FALSE)
93 return (TRUE);
95 na = uaddr2taddr(fdl->nconf, uaddr);
96 if (!na)
97 return (TRUE); /* punt, should never happen */
99 taddr.addr = *na;
100 taddr.qlen = 1;
101 (void) mutex_lock(&fdl->fd_lock);
102 fd = fdl->fd;
103 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
104 if (baddr == NULL) {
105 (void) mutex_unlock(&fdl->fd_lock);
106 netdir_free((char *)na, ND_ADDR);
107 return (TRUE);
109 if (t_bind(fd, &taddr, baddr) != 0) {
110 (void) mutex_unlock(&fdl->fd_lock);
111 netdir_free((char *)na, ND_ADDR);
112 (void) t_free((char *)baddr, T_BIND);
113 return (TRUE);
115 if (t_unbind(fd) != 0) {
116 /* Bad fd. Purge this fd */
117 (void) t_close(fd);
118 fdl->fd = t_open(fdl->nconf->nc_device, O_RDWR, NULL);
119 if (fdl->fd == -1)
120 fdl->check_binding = FALSE;
122 (void) mutex_unlock(&fdl->fd_lock);
123 ans = memcmp(taddr.addr.buf, baddr->addr.buf, baddr->addr.len);
124 netdir_free((char *)na, ND_ADDR);
125 (void) t_free((char *)baddr, T_BIND);
126 return (ans == 0 ? FALSE : TRUE);
130 * Keep open one more file descriptor for this transport, which
131 * will be used to determine whether the given service is up
132 * or not by trying to bind to the registered address.
133 * We are ignoring errors here. It trashes taddr and baddr;
134 * but that perhaps should not matter.
136 * We check for the following conditions:
137 * 1. Is it possible for t_bind to fail in the case where
138 * we bind to an already bound address and have any
139 * other error number besides TNOADDR.
140 * 2. If an address is specified in bind addr, can I bind to
141 * the same address.
142 * 3. If NULL is specified in bind addr, can I bind to the
143 * address to which the fd finally got bound.
146 add_bndlist(struct netconfig *nconf, struct t_bind *taddr, struct t_bind *baddr)
148 int fd;
149 struct fdlist *fdl;
150 struct netconfig *newnconf;
151 struct t_info tinfo;
152 struct t_bind tmpaddr;
154 newnconf = getnetconfigent(nconf->nc_netid);
155 if (newnconf == NULL)
156 return (-1);
157 fdl = (struct fdlist *)malloc((uint_t)sizeof (struct fdlist));
158 if (fdl == NULL) {
159 freenetconfigent(newnconf);
160 syslog(LOG_ERR, "no memory!");
161 return (-1);
163 (void) mutex_init(&fdl->fd_lock, USYNC_THREAD, NULL);
164 fdl->nconf = newnconf;
165 fdl->next = NULL;
166 if (fdhead == NULL) {
167 fdhead = fdl;
168 fdtail = fdl;
169 } else {
170 fdtail->next = fdl;
171 fdtail = fdl;
173 fdl->check_binding = FALSE;
174 if ((fdl->fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) < 0) {
176 * Note that we haven't dequeued this entry nor have we freed
177 * the netconfig structure.
179 if (debugging) {
180 fprintf(stderr,
181 "%s: add_bndlist cannot open connection: %s",
182 nconf->nc_netid, t_errlist[t_errno]);
184 return (-1);
187 /* Set the qlen only for cots transports */
188 switch (tinfo.servtype) {
189 case T_COTS:
190 case T_COTS_ORD:
191 taddr->qlen = 1;
192 break;
193 case T_CLTS:
194 taddr->qlen = 0;
195 break;
196 default:
197 goto error;
200 if (t_bind(fdl->fd, taddr, baddr) != 0) {
201 if (t_errno == TNOADDR) {
202 fdl->check_binding = TRUE;
203 return (0); /* All is fine */
205 /* Perhaps condition #1 */
206 if (debugging) {
207 fprintf(stderr, "%s: add_bndlist cannot bind (1): %s",
208 nconf->nc_netid, t_errlist[t_errno]);
210 goto not_bound;
213 /* Condition #2 */
214 if (!memcmp(taddr->addr.buf, baddr->addr.buf,
215 (int)baddr->addr.len)) {
216 goto not_bound;
219 /* Condition #3 */
220 t_unbind(fdl->fd);
221 /* Set the qlen only for cots transports */
222 switch (tinfo.servtype) {
223 case T_COTS:
224 case T_COTS_ORD:
225 tmpaddr.qlen = 1;
226 break;
227 case T_CLTS:
228 tmpaddr.qlen = 0;
229 break;
230 default:
231 goto error;
233 tmpaddr.addr.len = tmpaddr.addr.maxlen = 0;
234 tmpaddr.addr.buf = NULL;
235 if (t_bind(fdl->fd, &tmpaddr, taddr) != 0) {
236 if (debugging) {
237 fprintf(stderr, "%s: add_bndlist cannot bind (2): %s",
238 nconf->nc_netid, t_errlist[t_errno]);
240 goto error;
242 /* Now fdl->fd is bound to a transport chosen address */
243 if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) < 0) {
244 if (debugging) {
245 fprintf(stderr,
246 "%s: add_bndlist cannot open connection: %s",
247 nconf->nc_netid, t_errlist[t_errno]);
249 goto error;
251 if (t_bind(fd, taddr, baddr) != 0) {
252 if (t_errno == TNOADDR) {
254 * This transport is schizo. Previously it handled a
255 * request to bind to an already bound transport by
256 * returning a different bind address, and now it's
257 * returning a TNOADDR for essentially the same
258 * request. The spec may allow this behavior, so
259 * we'll just assume we can't do bind checking with
260 * this transport.
262 t_close(fd);
263 goto not_bound;
265 if (debugging) {
266 fprintf(stderr, "%s: add_bndlist cannot bind (3): %s",
267 nconf->nc_netid, t_errlist[t_errno]);
269 t_close(fd);
270 goto error;
272 t_close(fd);
273 if (!memcmp(taddr->addr.buf, baddr->addr.buf,
274 (int)baddr->addr.len)) {
275 switch (tinfo.servtype) {
276 case T_COTS:
277 case T_COTS_ORD:
278 if (baddr->qlen == 1) {
279 goto not_bound;
281 break;
282 case T_CLTS:
283 goto not_bound;
284 default:
285 goto error;
289 t_unbind(fdl->fd);
290 fdl->check_binding = TRUE;
291 return (0);
293 not_bound:
294 t_close(fdl->fd);
295 fdl->fd = -1;
296 return (1);
298 error:
299 t_close(fdl->fd);
300 fdl->fd = -1;
301 return (-1);
304 bool_t
305 is_bound(char *netid, char *uaddr)
307 struct fdlist *fdl;
309 for (fdl = fdhead; fdl; fdl = fdl->next)
310 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
311 break;
312 if (fdl == NULL)
313 return (TRUE);
314 return (check_bound(fdl, uaddr));
317 /* Return pointer to port string in the universal address */
318 #define UADDR_PRT_INDX(UADDR, PORT) { \
319 PORT = strrchr(UADDR, '.'); \
320 while (*--PORT != '.'); }
322 * Returns NULL if there was some system error.
323 * Returns "" if the address was not bound, i.e the server crashed.
324 * Returns the merged address otherwise.
326 char *
327 mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
329 struct fdlist *fdl;
330 struct nd_mergearg ma;
331 int stat;
333 for (fdl = fdhead; fdl; fdl = fdl->next)
334 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
335 break;
336 if (fdl == NULL)
337 return (NULL);
338 if (check_bound(fdl, uaddr) == FALSE)
339 /* that server died */
340 return (nullstring);
342 * If saddr is not NULL, the remote client may have included the
343 * address by which it contacted us. Use that for the "client" uaddr,
344 * otherwise use the info from the SVCXPRT.
346 if (saddr != NULL) {
347 ma.c_uaddr = saddr;
348 } else {
350 /* retrieve the client's address */
351 ma.c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
352 if (ma.c_uaddr == NULL) {
353 syslog(LOG_ERR, "taddr2uaddr failed for %s: %s",
354 fdl->nconf->nc_netid, netdir_sperror());
355 return (NULL);
360 /* Not an INET address? */
361 if ((strcmp(fdl->nconf->nc_protofmly, NC_INET) != 0) &&
362 (strcmp(fdl->nconf->nc_protofmly, NC_INET6) != 0)) {
363 ma.s_uaddr = uaddr;
364 stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
366 /* Inet address, but no xp_ltaddr */
367 else if ((ma.s_uaddr = taddr2uaddr(fdl->nconf,
368 &(xprt)->xp_ltaddr)) == NULL) {
369 ma.s_uaddr = uaddr;
370 stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
371 } else {
373 * (xprt)->xp_ltaddr contains portmap's port address.
374 * Overwrite this with actual application's port address
375 * before returning to the caller.
377 char *s_uport, *uport;
379 /* Get the INET/INET6 address part from ma.s_uaddr */
380 UADDR_PRT_INDX(ma.s_uaddr, s_uport);
381 *s_uport = '\0';
383 /* Get the port info from uaddr */
384 UADDR_PRT_INDX(uaddr, uport);
386 ma.m_uaddr = malloc(strlen(ma.s_uaddr) + strlen(uport) + 1);
387 if (ma.m_uaddr == NULL) {
388 syslog(LOG_ERR, "mergeaddr: no memory!");
389 free(ma.s_uaddr);
390 if (saddr == NULL)
391 free(ma.c_uaddr);
392 return (NULL);
395 /* Copy IP address into the Universal address holder */
396 strcpy(ma.m_uaddr, ma.s_uaddr);
397 /* Append port info to the Universal address holder */
398 strcat(ma.m_uaddr, uport);
399 free(ma.s_uaddr);
400 stat = 0;
402 if (saddr == NULL) {
403 free(ma.c_uaddr);
405 if (stat) {
406 syslog(LOG_ERR, "netdir_merge failed for %s: %s",
407 fdl->nconf->nc_netid, netdir_sperror());
408 return (NULL);
411 return (ma.m_uaddr);
415 * Returns a netconf structure from its internal list. This
416 * structure should not be freed.
418 struct netconfig *
419 rpcbind_get_conf(char *netid)
421 struct fdlist *fdl;
423 for (fdl = fdhead; fdl; fdl = fdl->next)
424 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
425 break;
426 if (fdl == NULL)
427 return (NULL);
428 return (fdl->nconf);