Add the management part of address selection policy described in RFC
[dragonfly.git] / usr.sbin / rpcbind / check_bound.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  * @(#)check_bound.c    1.15    93/07/05 SMI; 1.11 89/04/21 Copyr 1989 Sun Micro
30  * $NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $
31  * $FreeBSD: src/usr.sbin/rpcbind/check_bound.c,v 1.5 2007/11/07 10:53:39 kevlo Exp $
32  * $DragonFly$
33  */
34 /*
35  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
36  */
37
38 /*
39  * check_bound.c
40  * Checks to see whether the program is still bound to the
41  * claimed address and returns the univeral merged address
42  *
43  */
44
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <rpc/rpc.h>
48 #include <stdio.h>
49 #include <netconfig.h>
50 #include <syslog.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54
55 #include "rpcbind.h"
56
57 struct fdlist {
58         int fd;
59         struct netconfig *nconf;
60         struct fdlist *next;
61         int check_binding;
62 };
63
64 static struct fdlist *fdhead;   /* Link list of the check fd's */
65 static struct fdlist *fdtail;
66 static char *nullstring = "";
67
68 static bool_t   check_bound(struct fdlist *, char *uaddr);
69
70 /*
71  * Returns 1 if the given address is bound for the given addr & transport
72  * For all error cases, we assume that the address is bound
73  * Returns 0 for success.
74  */
75 static bool_t
76 check_bound(struct fdlist *fdl, char *uaddr)
77 {
78         int fd;
79         struct netbuf *na;
80         int ans;
81
82         if (fdl->check_binding == FALSE)
83                 return (TRUE);
84
85         na = uaddr2taddr(fdl->nconf, uaddr);
86         if (!na)
87                 return (TRUE); /* punt, should never happen */
88
89         fd = __rpc_nconf2fd(fdl->nconf);
90         if (fd < 0) {
91                 free(na->buf);
92                 free(na);
93                 return (TRUE);
94         }
95
96         ans = bind(fd, (struct sockaddr *)na->buf, na->len);
97
98         close(fd);
99         free(na->buf);
100         free(na);
101
102         return (ans == 0 ? FALSE : TRUE);
103 }
104
105 int
106 add_bndlist(struct netconfig *nconf, struct netbuf *baddr __unused)
107 {
108         struct fdlist *fdl;
109         struct netconfig *newnconf;
110
111         newnconf = getnetconfigent(nconf->nc_netid);
112         if (newnconf == NULL)
113                 return (-1);
114         fdl = malloc(sizeof (struct fdlist));
115         if (fdl == NULL) {
116                 freenetconfigent(newnconf);
117                 syslog(LOG_ERR, "no memory!");
118                 return (-1);
119         }
120         fdl->nconf = newnconf;
121         fdl->next = NULL;
122         if (fdhead == NULL) {
123                 fdhead = fdl;
124                 fdtail = fdl;
125         } else {
126                 fdtail->next = fdl;
127                 fdtail = fdl;
128         }
129         /* XXX no bound checking for now */
130         fdl->check_binding = FALSE;
131
132         return 0;
133 }
134
135 bool_t
136 is_bound(char *netid, char *uaddr)
137 {
138         struct fdlist *fdl;
139
140         for (fdl = fdhead; fdl; fdl = fdl->next)
141                 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
142                         break;
143         if (fdl == NULL)
144                 return (TRUE);
145         return (check_bound(fdl, uaddr));
146 }
147
148 /*
149  * Returns NULL if there was some system error.
150  * Returns "" if the address was not bound, i.e the server crashed.
151  * Returns the merged address otherwise.
152  */
153 char *
154 mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
155 {
156         struct fdlist *fdl;
157         char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
158
159         for (fdl = fdhead; fdl; fdl = fdl->next)
160                 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
161                         break;
162         if (fdl == NULL)
163                 return (NULL);
164         if (check_bound(fdl, uaddr) == FALSE)
165                 /* that server died */
166                 return (nullstring);
167         /*
168          * If saddr is not NULL, the remote client may have included the
169          * address by which it contacted us.  Use that for the "client" uaddr,
170          * otherwise use the info from the SVCXPRT.
171          */
172         if (saddr != NULL) {
173                 c_uaddr = saddr;
174         } else {
175                 c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
176                 if (c_uaddr == NULL) {
177                         syslog(LOG_ERR, "taddr2uaddr failed for %s",
178                                 fdl->nconf->nc_netid);
179                         return (NULL);
180                 }
181                 allocated_uaddr = c_uaddr;
182         }
183
184 #ifdef ND_DEBUG
185         if (debugging) {
186                 if (saddr == NULL) {
187                         fprintf(stderr, "mergeaddr: client uaddr = %s\n",
188                             c_uaddr);
189                 } else {
190                         fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
191                             c_uaddr);
192                 }
193         }
194 #endif
195         s_uaddr = uaddr;
196         /*
197          * This is all we should need for IP 4 and 6
198          */
199         m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
200 #ifdef ND_DEBUG
201         if (debugging)
202                 fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
203                                 uaddr, m_uaddr);
204 #endif
205         if (allocated_uaddr != NULL)
206                 free(allocated_uaddr);
207         return (m_uaddr);
208 }
209
210 /*
211  * Returns a netconf structure from its internal list.  This
212  * structure should not be freed.
213  */
214 struct netconfig *
215 rpcbind_get_conf(char *netid)
216 {
217         struct fdlist *fdl;
218
219         for (fdl = fdhead; fdl; fdl = fdl->next)
220                 if (strcmp(fdl->nconf->nc_netid, netid) == 0)
221                         break;
222         if (fdl == NULL)
223                 return (NULL);
224         return (fdl->nconf);
225 }