Initial revision
[nfs-utils.git] / support / export / client.c
1 /*
2  * support/export/client.c
3  *
4  * Maintain list of nfsd clients.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include "config.h"
10
11 #include <sys/types.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <netdb.h>
17 #include "xmalloc.h"
18 #include "misc.h"
19 #include "nfslib.h"
20 #include "exportfs.h"
21
22 /* netgroup stuff never seems to be defined in any header file. Linux is
23  * not alone in this.
24  */
25 #if !defined(__GLIBC__) || __GLIBC__ < 2
26 extern int      innetgr(char *netgr, char *host, char *, char *);
27 #endif
28 static void     client_init(nfs_client *clp, const char *hname,
29                                         struct hostent *hp);
30 static int      client_checkaddr(nfs_client *clp, struct in_addr addr);
31
32 nfs_client      *clientlist[MCL_MAXTYPES] = { NULL, };
33
34
35 nfs_client *
36 client_lookup(char *hname)
37 {
38         nfs_client      *clp = NULL;
39         int             htype;
40         struct hostent  *hp = NULL;
41
42         htype = client_gettype(hname);
43
44         if (htype == MCL_FQDN) {
45                 hp = gethostbyname(hname);
46                 if (hp == NULL || hp->h_addrtype != AF_INET) {
47                         xlog(L_ERROR, "%s has non-inet addr", hname);
48                         return NULL;
49                 }
50                 hp = hostent_dup (hp);
51                 hname = (char *) hp->h_name;
52
53                 for (clp = clientlist[htype]; clp; clp = clp->m_next) {
54                         if (client_check(clp, hp))
55                                 break;
56                 }
57         } else {
58                 for (clp = clientlist[htype]; clp; clp = clp->m_next) {
59                         if (strcmp(hname, clp->m_hostname)==0)
60                                 break;
61                 }
62         }
63
64         if (!clp) {
65                 clp = (nfs_client *) xmalloc(sizeof(*clp));
66                 memset(clp, 0, sizeof(*clp));
67                 clp->m_type = htype;
68                 client_init(clp, hname, NULL);
69                 client_add(clp);
70         }
71
72         if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
73                 char    **ap = hp->h_addr_list;
74                 int     i;
75
76                 for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
77                         clp->m_addrlist[i] = *(struct in_addr *)*ap;
78                 clp->m_naddr = i;
79         }
80
81         if (hp)
82                 free (hp);
83
84         return clp;
85 }
86
87 nfs_client *
88 client_dup(nfs_client *clp, struct hostent *hp)
89 {
90         nfs_client              *new;
91
92         new = (nfs_client *) xmalloc(sizeof(*new));
93         memcpy(new, clp, sizeof(*new));
94         new->m_type = MCL_FQDN;
95
96         client_init(new, (char *) hp->h_name, hp);
97         client_add(new);
98         return new;
99 }
100
101 static void
102 client_init(nfs_client *clp, const char *hname, struct hostent *hp)
103 {
104         if (hp) {
105                 strncpy(clp->m_hostname, hp->h_name,
106                         sizeof (clp->m_hostname) -  1);
107         } else {
108                 strncpy(clp->m_hostname, hname,
109                         sizeof (clp->m_hostname) - 1);
110         }
111         clp->m_hostname[sizeof (clp->m_hostname) - 1] = '\0';
112
113         clp->m_exported = 0;
114         clp->m_count = 0;
115
116         if (clp->m_type == MCL_SUBNETWORK) {
117                 char    *cp = strchr(clp->m_hostname, '/');
118
119                 *cp = '\0';
120                 clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
121                 clp->m_addrlist[1].s_addr = inet_addr(cp+1);
122                 *cp = '/';
123                 clp->m_naddr = 0;
124         } else if (!hp) {
125                 clp->m_naddr = 0;
126         } else {
127                 char    **ap = hp->h_addr_list;
128                 int     i;
129
130                 for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
131                         clp->m_addrlist[i] = *(struct in_addr *)*ap;
132                 }
133                 clp->m_naddr = i;
134         }
135 }
136
137 void
138 client_add(nfs_client *clp)
139 {
140         nfs_client      **cpp;
141
142         if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
143                 xlog(L_FATAL, "unknown client type in client_add");
144         cpp = clientlist + clp->m_type;
145         while (*cpp)
146                 cpp = &((*cpp)->m_next);
147         clp->m_next = NULL;
148         *cpp = clp;
149 }
150
151 void
152 client_release(nfs_client *clp)
153 {
154         if (clp->m_count <= 0)
155                 xlog(L_FATAL, "client_free: m_count <= 0!");
156         clp->m_count--;
157 }
158
159 void
160 client_freeall(void)
161 {
162         nfs_client      *clp, **head;
163         int             i;
164
165         for (i = 0; i < MCL_MAXTYPES; i++) {
166                 head = clientlist + i;
167                 while (*head) {
168                         *head = (clp = *head)->m_next;
169                         xfree(clp);
170                 }
171         }
172 }
173
174 nfs_client *
175 client_find(struct hostent *hp)
176 {
177         nfs_client      *clp;
178         int             i;
179
180         for (i = 0; i < MCL_MAXTYPES; i++) {
181                 for (clp = clientlist[i]; clp; clp = clp->m_next) {
182                         if (!client_check(clp, hp))
183                                 continue;
184 #ifdef notdef
185                         if (clp->m_type == MCL_FQDN)
186                                 return clp;
187                         return client_dup(clp, hp);
188 #else
189                         return clp;
190 #endif
191                 }
192         }
193         return NULL;
194 }
195
196 /*
197  * Match a host (given its hostent record) to a client record. This
198  * is usually called from mountd.
199  */
200 int
201 client_check(nfs_client *clp, struct hostent *hp)
202 {
203         char    *hname = (char *) hp->h_name;
204         char    *cname = clp->m_hostname;
205         char    **ap;
206
207         switch (clp->m_type) {
208         case MCL_FQDN:
209         case MCL_SUBNETWORK:
210                 for (ap = hp->h_addr_list; *ap; ap++) {
211                         if (client_checkaddr(clp, *(struct in_addr *) *ap))
212                                 return 1;
213                 }
214                 return 0;
215         case MCL_WILDCARD:
216                 if (wildmat(hname, cname))
217                         return 1;
218                 else {
219                         for (ap = hp->h_aliases; *ap; ap++)
220                                 if (wildmat(*ap, cname))
221                                         return 1;
222                 }
223                 return 0;
224         case MCL_NETGROUP:
225 #ifdef HAVE_INNETGR
226                 {
227                         char    *dot;
228                         int     match;
229
230                         /* First, try to match the hostname without
231                          * splitting off the domain */
232                         if (innetgr(cname+1, hname, NULL, NULL))
233                                 return 1;
234
235                         /* Okay, strip off the domain (if we have one) */
236                         if ((dot = strchr(hname, '.')) == NULL)
237                                 return 0;
238
239                         *dot = '\0';
240                         match = innetgr(cname+1, hname, NULL, dot + 1);
241                         *dot = '.';
242
243                         return match;
244                 }
245 #else
246                 return 0;
247 #endif
248         case MCL_ANONYMOUS:
249                 return 1;
250         default:
251                 xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
252         }
253
254         return 0;
255 }
256
257 static int
258 client_checkaddr(nfs_client *clp, struct in_addr addr)
259 {
260         int     i;
261
262         switch (clp->m_type) {
263         case MCL_FQDN:
264                 for (i = 0; i < clp->m_naddr; i++) {
265                         if (clp->m_addrlist[i].s_addr == addr.s_addr)
266                                 return 1;
267                 }
268                 return 0;
269         case MCL_SUBNETWORK:
270                 return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
271                         & clp->m_addrlist[1].s_addr);
272         }
273         return 0;
274 }
275
276 int
277 client_gettype(char *ident)
278 {
279         char    *sp;
280
281         if (ident[0] == '\0')
282                 return MCL_ANONYMOUS;
283         if (ident[0] == '@') {
284 #ifndef HAVE_INNETGR
285                 xlog(L_WARNING, "netgroup support not compiled in");
286 #endif
287                 return MCL_NETGROUP;
288         }
289         for (sp = ident; *sp; sp++) {
290                 if (*sp == '*' || *sp == '?' || *sp == '[')
291                         return MCL_WILDCARD;
292                 if (*sp == '/')
293                         return MCL_SUBNETWORK;
294                 if (*sp == '\\' && sp[1])
295                         sp++;
296         }
297         return MCL_FQDN;
298 }