mountd: Replace "struct hostent" with "struct addrinfo"
[nfs-utils.git] / support / export / export.c
1 /*
2  * support/export/export.c
3  *
4  * Maintain list of exported file systems.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <netinet/in.h>
17 #include <stdlib.h>
18 #include "xmalloc.h"
19 #include "nfslib.h"
20 #include "exportfs.h"
21
22 exp_hash_table exportlist[MCL_MAXTYPES] = {{NULL, {{NULL,NULL}, }}, }; 
23 static int export_hash(char *);
24
25 static void     export_init(nfs_export *exp, nfs_client *clp,
26                                         struct exportent *nep);
27 static int      export_check(const nfs_export *exp, const struct addrinfo *ai,
28                                 const char *path);
29 static nfs_export *
30                 export_allowed_internal(const struct addrinfo *ai,
31                                 const char *path);
32
33 static void
34 export_free(nfs_export *exp)
35 {
36         xfree(exp->m_export.e_squids);
37         xfree(exp->m_export.e_sqgids);
38         free(exp->m_export.e_mountpoint);
39         free(exp->m_export.e_fslocdata);
40
41         xfree(exp->m_export.e_hostname);
42         xfree(exp);
43 }
44
45 static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
46 {
47         if (exp->m_export.e_flags != eep->e_flags) {
48                 xlog(L_ERROR, "incompatible duplicated export entries:");
49                 xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
50                                 eep->e_path, eep->e_flags);
51                 xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
52                                 exp->m_export.e_path, exp->m_export.e_flags);
53         } else {
54                 xlog(L_ERROR, "duplicated export entries:");
55                 xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
56                 xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
57                                 exp->m_export.e_path);
58         }
59 }
60
61 int
62 export_read(char *fname)
63 {
64         struct exportent        *eep;
65         nfs_export              *exp;
66
67         setexportent(fname, "r");
68         while ((eep = getexportent(0,1)) != NULL) {
69                 exp = export_lookup(eep->e_hostname, eep->e_path, 0);
70                 if (!exp)
71                         export_create(eep, 0);
72                 else
73                         warn_duplicated_exports(exp, eep);
74         }
75         endexportent();
76         return 0;
77 }
78
79 /*
80  * Create an in-core export struct from an export entry.
81  */
82 nfs_export *
83 export_create(struct exportent *xep, int canonical)
84 {
85         nfs_client      *clp;
86         nfs_export      *exp;
87
88         if (!(clp = client_lookup(xep->e_hostname, canonical))) {
89                 /* bad export entry; complaint already logged */
90                 return NULL;
91         }
92         exp = (nfs_export *) xmalloc(sizeof(*exp));
93         export_init(exp, clp, xep);
94         export_add(exp);
95
96         return exp;
97 }
98
99 static void
100 export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
101 {
102         struct exportent        *e = &exp->m_export;
103
104         dupexportent(e, nep);
105         if (nep->e_hostname)
106                 e->e_hostname = xstrdup(nep->e_hostname);
107
108         exp->m_exported = 0;
109         exp->m_xtabent = 0;
110         exp->m_mayexport = 0;
111         exp->m_changed = 0;
112         exp->m_warned = 0;
113         exp->m_client = clp;
114         clp->m_count++;
115 }
116
117 /*
118  * Duplicate exports data. The in-core export struct retains the
119  * original hostname from /etc/exports, while the in-core client struct
120  * gets the newly found FQDN.
121  */
122 static nfs_export *
123 export_dup(nfs_export *exp, const struct addrinfo *ai)
124 {
125         nfs_export              *new;
126         nfs_client              *clp;
127
128         new = (nfs_export *) xmalloc(sizeof(*new));
129         memcpy(new, exp, sizeof(*new));
130         dupexportent(&new->m_export, &exp->m_export);
131         if (exp->m_export.e_hostname)
132                 new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
133         clp = client_dup(exp->m_client, ai);
134         if (clp == NULL) {
135                 export_free(new);
136                 return NULL;
137         }
138         clp->m_count++;
139         new->m_client = clp;
140         new->m_mayexport = exp->m_mayexport;
141         new->m_exported = 0;
142         new->m_xtabent = 0;
143         new->m_changed = 0;
144         new->m_warned = 0;
145         export_add(new);
146
147         return new;
148 }
149
150 /*
151  * Add export entry to hash table
152  */
153 void 
154 export_add(nfs_export *exp)
155 {
156         exp_hash_table *p_tbl;
157         exp_hash_entry *p_hen;
158         nfs_export *p_next;
159
160         int type = exp->m_client->m_type;
161         int pos;
162
163         pos = export_hash(exp->m_export.e_path);
164         p_tbl = &(exportlist[type]); /* pointer to hash table */
165         p_hen = &(p_tbl->entries[pos]); /* pointer to hash table entry */
166
167         if (!(p_hen->p_first)) { /* hash table entry is empty */ 
168                 p_hen->p_first = exp;
169                 p_hen->p_last  = exp;
170
171                 exp->m_next = p_tbl->p_head;
172                 p_tbl->p_head = exp;
173         } else { /* hash table entry is NOT empty */
174                 p_next = p_hen->p_last->m_next;
175                 p_hen->p_last->m_next = exp;
176                 exp->m_next = p_next;
177                 p_hen->p_last = exp;
178         }
179 }
180
181 /**
182  * export_find - find or create a suitable nfs_export for @ai and @path
183  * @ai: pointer to addrinfo for client
184  * @path: '\0'-terminated ASCII string containing export path
185  *
186  * Returns a pointer to nfs_export data matching @ai and @path,
187  * or NULL if an error occurs.
188  */
189 nfs_export *
190 export_find(const struct addrinfo *ai, const char *path)
191 {
192         nfs_export      *exp;
193         int             i;
194
195         for (i = 0; i < MCL_MAXTYPES; i++) {
196                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
197                         if (!export_check(exp, ai, path))
198                                 continue;
199                         if (exp->m_client->m_type == MCL_FQDN)
200                                 return exp;
201                         return export_dup(exp, ai);
202                 }
203         }
204
205         return NULL;
206 }
207
208 static nfs_export *
209 export_allowed_internal(const struct addrinfo *ai, const char *path)
210 {
211         nfs_export      *exp;
212         int             i;
213
214         for (i = 0; i < MCL_MAXTYPES; i++) {
215                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
216                         if (!exp->m_mayexport ||
217                             !export_check(exp, ai, path))
218                                 continue;
219                         return exp;
220                 }
221         }
222
223         return NULL;
224 }
225
226 /**
227  * export_allowed - determine if this export is allowed
228  * @ai: pointer to addrinfo for client
229  * @path: '\0'-terminated ASCII string containing export path
230  *
231  * Returns a pointer to nfs_export data matching @ai and @path,
232  * or NULL if the export is not allowed.
233  */
234 nfs_export *
235 export_allowed(const struct addrinfo *ai, const char *path)
236 {
237         nfs_export              *exp;
238         char                    epath[MAXPATHLEN+1];
239         char                    *p = NULL;
240
241         if (path [0] != '/') return NULL;
242
243         strncpy(epath, path, sizeof (epath) - 1);
244         epath[sizeof (epath) - 1] = '\0';
245
246         /* Try the longest matching exported pathname. */
247         while (1) {
248                 exp = export_allowed_internal(ai, epath);
249                 if (exp)
250                         return exp;
251                 /* We have to treat the root, "/", specially. */
252                 if (p == &epath[1]) break;
253                 p = strrchr(epath, '/');
254                 if (p == epath) p++;
255                 *p = '\0';
256         }
257
258         return NULL;
259 }
260
261 /*
262  * Search hash table for export entry. 
263  */  
264 nfs_export *
265 export_lookup(char *hname, char *path, int canonical) 
266 {
267         nfs_client *clp;
268         nfs_export *exp;
269         exp_hash_entry *p_hen;
270
271         int pos;
272
273         clp = client_lookup(hname, canonical);
274         if(clp == NULL)
275                 return NULL;
276
277         pos = export_hash(path);
278         p_hen = &(exportlist[clp->m_type].entries[pos]); 
279         for(exp = p_hen->p_first; exp && (exp != p_hen->p_last->m_next); 
280                         exp = exp->m_next) {
281                 if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path)) {
282                         return exp;
283                 }
284         }
285         return NULL;
286 }
287
288 static int
289 export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path)
290 {
291         if (strcmp(path, exp->m_export.e_path))
292                 return 0;
293
294         return client_check(exp->m_client, ai);
295 }
296
297 /**
298  * export_freeall - deallocate all nfs_export records
299  *
300  */
301 void
302 export_freeall(void)
303 {
304         nfs_export      *exp, *nxt;
305         int             i, j;
306
307         for (i = 0; i < MCL_MAXTYPES; i++) {
308                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
309                         nxt = exp->m_next;
310                         client_release(exp->m_client);
311                         export_free(exp);
312                 }
313                 for (j = 0; j < HASH_TABLE_SIZE; j++) {
314                         exportlist[i].entries[j].p_first = NULL;
315                         exportlist[i].entries[j].p_last = NULL;
316                 }
317                 exportlist[i].p_head = NULL;
318         }
319         client_freeall();
320 }
321
322 /*
323  * Compute and returns integer from string. 
324  * Note: Its understood the smae integers can be same for 
325  *       different strings, but it should not matter.
326  */
327 static unsigned int 
328 strtoint(char *str)
329 {
330         int i = 0;
331         unsigned int n = 0;
332
333         while ( str[i] != '\0') {
334                 n+=((int)str[i])*i;
335                 i++;
336         }
337         return n;
338 }
339
340 /*
341  * Hash function
342  */
343 static int 
344 export_hash(char *str)
345 {
346         int num = strtoint(str);
347
348         return num % HASH_TABLE_SIZE;
349 }