Define and use get_reliable_hostbyname
[nfs-utils.git] / support / nfs / clients.c
1 /*
2  * support/nfs/nfsclient.c
3  *
4  * Parse the nfsclients file.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include "config.h"
10
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <syslog.h>
15 #include <ctype.h>
16 #include "xmalloc.h"
17 #include "nfslib.h"
18 #include "exportfs.h"
19 #include "xio.h"
20
21 static char     *cfname = NULL;
22 static XFILE    *cfp = NULL;
23 static int      *squash_uids = NULL,
24                 *squash_gids = NULL;
25 static int      squash_uidlen = 0,
26                 squash_gidlen = 0;
27 static char     *hosts = NULL;
28
29 static int      parsesquash(char *list, int **idp, int *lenp);
30 static int      parsenum(char **cpp);
31 static int      parsekey(struct nfskey *keyp, char *str);
32 static int      hexdigit(char c);
33 static int      gettag(char *tag, int len);
34 static int      getattr(char *attr, int alen, char *value, int vlen);
35 static void     syntaxerr(char *msg);
36
37 #ifndef isblank
38 #define isblank(c)      ((c) == ' ' || (c) == '\t')
39 #endif
40
41 void
42 setnfsclntent(char *fname)
43 {
44         if (cfp)
45                 xfclose(cfp);
46         if (!fname)
47                 fname = _PATH_NFSCLIENTS;
48         if ((cfp = xfopen(fname)) == NULL)
49                 xlog(L_ERROR, "can't open %s for reading", fname);
50         cfname = strdup(fname);
51 }
52
53 struct nfsclntent *
54 getnfsclntent(void)
55 {
56         static struct nfsclntent cle;
57         static char     *hostptr = NULL;
58         char            attr[32], val[512], *sp;
59         int             ok;
60
61         if (!cfp)
62                 endnfsclntent();
63
64 again:
65         if (hosts) {
66                 if (hostptr)
67                         goto nexthost;
68                 xfree(hosts);
69                 hosts = NULL;
70         }
71
72         if ((ok = gettag(cle.c_tag, sizeof(cle.c_tag))) < 0)
73                 syntaxerr("expected tag");
74         if (ok <= 0)
75                 return NULL;
76
77         cle.c_hostname[0] = '\0';
78         cle.c_fhkey.k_type = CLE_KEY_NONE;
79         cle.c_mapping = CLE_MAP_IDENT;
80         cle.c_anonuid = -2;
81         cle.c_anongid = -2;
82
83         if (squash_uids)
84                 xfree(squash_uids);
85         if (squash_gids)
86                 xfree(squash_gids);
87         squash_uids = squash_gids = NULL;
88         squash_uidlen = squash_gidlen = 0;
89
90         while (ok) {
91                 if ((ok = getattr(attr, sizeof(attr), val, sizeof(val))) < 0)
92                         return NULL;
93                 if (!ok)
94                         break;
95                 if (attr[0] == 'h' && !strcmp(attr, "hosts")) {
96                         int     l0 = hosts? strlen(hosts) : 0;
97
98                         hosts = (char *) xrealloc(hosts, l0+strlen(val)+2);
99                         if (l0)
100                                 hosts[l0++] = ':';
101                         strcpy(hosts+l0, val);
102                 } else
103                 if (attr[0] == 'f' && !strcmp(attr, "fhmac")) {
104                         if (!parsekey(&cle.c_fhkey, val))
105                                 return NULL;
106                 } else
107                 if (attr[0] == 'm' && !strcmp(attr, "mapping")) {
108                         if (!strcmp(val, "identity"))
109                                 cle.c_mapping = CLE_MAP_IDENT;
110                         else if (!strcmp(val, "file"))
111                                 cle.c_mapping = CLE_MAP_FILE;
112                         else if (!strcmp(val, "daemon"))
113                                 cle.c_mapping = CLE_MAP_UGIDD;
114                         else {
115                                 syntaxerr("invalid mapping type");
116                                 return NULL;
117                         }
118                 } else
119                 if (attr[0] == 's' && !strcmp(attr, "squash_uids")) {
120                         if (!parsesquash(val, &squash_uids, &squash_uidlen))
121                                 return NULL;
122                 } else
123                 if (attr[0] == 's' && !strcmp(attr, "squash_gids")) {
124                         if (!parsesquash(val, &squash_gids, &squash_gidlen))
125                                 return NULL;
126                 } else
127                 if (attr[0] == 'a' && !strcmp(attr, "anonuid"))
128                         cle.c_anonuid = atoi(val);
129                 else
130                 if (attr[0] == 'a' && !strcmp(attr, "anongid"))
131                         cle.c_anongid = atoi(val);
132                 else
133                         syntaxerr("unknown attribute");
134         }
135
136         cle.c_squashuids = squash_uids;
137         cle.c_squashgids = squash_gids;
138
139         /* This is the anon entry */
140         if (!hosts) {
141                 if (strcmp(cle.c_tag, "anonymous")) {
142                         xlog(L_ERROR,
143                              "%s:%d: entry %s allows anonymous access.  Ignored.",
144                              cfname, xfp->x_line, cle.c_tag);
145                         goto again;
146                 }
147                 return &cle;
148         }
149         hostptr = hosts;
150
151 nexthost:
152         if (*hostptr == ':' && strcmp(cle.c_tag, "anonymous")) {
153                 xlog(L_ERROR,
154                      "%s:%d: entry %s allows anonymous access.  Ignored.",
155                      cfname, cfp->x_line, cle.c_tag);
156                 while (*hostptr == ':')
157                         hostptr++;
158         }
159
160         /* Ignore trailing colons */
161         if (!*hostptr) {
162                 hostptr = NULL;
163                 goto again;
164         }
165
166         sp = hostptr;
167         hostptr = strchr(hostptr, ':');
168         if (hostptr)
169                 *hostptr++ = '\0';
170         strncpy(cle.c_hostname, sp, sizeof(cle.c_hostname) - 1);
171         cle.c_hostname [sizeof(cle.c_hostname) - 1] = '\0';
172         return &cle;
173 }
174
175 void
176 endnfsclntent(void)
177 {
178         if (cfname)
179                 free(cfname);
180         if (cfp)
181                 xfclose(cfp);
182         if (squash_uids)
183                 xfree(squash_uids);
184         if (squash_gids)
185                 xfree(squash_gids);
186         if (hosts)
187                 xfree(hosts);
188         cfname = NULL;
189         cfp = NULL;
190         squash_uids = NULL;
191         squash_gids = NULL;
192         hosts = NULL;
193 }
194
195 static int
196 parsekey(struct nfskey *keyp, char *str)
197 {
198         char    *sp;
199         int     i, l, x0, x1;
200
201
202         if ((sp = strchr(str, ':')) != NULL)
203                 *sp++ = '\0';
204         if (!strcmp(str, "null"))
205                 keyp->k_type = CLE_KEY_NULL;
206         else if (!strcmp(str, "md5"))
207                 keyp->k_type = CLE_KEY_MD5;
208         else if (!strcmp(str, "sha"))
209                 keyp->k_type = CLE_KEY_SHA;
210         else {
211                 syntaxerr("unknown key type");
212                 return 0;
213         }
214         if (keyp->k_type == CLE_KEY_NULL) {
215                 keyp->k_len = 0;
216                 if (sp)
217                         syntaxerr("unexpected key data for null key");
218                 return sp? 0 : 1;
219         } else if (sp) {
220                 if ((l = strlen(sp)) & 1) {
221                         syntaxerr("odd key length");
222                         return 0;
223                 }
224
225                 l >>= 1;
226                 for (i = 0; i < l && i < sizeof(keyp->k_key); i++, sp += 2) {
227                         if ((x0 = hexdigit(sp[0])) == 0xff ||
228                             (x1 = hexdigit(sp[1])) == 0xff) {
229                                 syntaxerr("bad key digit");
230                                 return 0;
231                         }
232                         keyp->k_key[i] = (x0 << 4) | x1;
233                 }
234                 keyp->k_len = i;
235                 return 1;
236         }
237         return 0;
238 }
239
240 static int
241 hexdigit(char c)
242 {
243         if ((c = tolower(c)) >= '0' && c <= '9')
244                 return c - '0';
245         if (c >= 'a' && c <= 'f')
246                 return c - 'a' + 10;
247         return 0xff;
248 }
249
250 static int
251 parsesquash(char *list, int **idp, int *lenp)
252 {
253         char    *cp = list;
254         int     id0, id1;
255         int     len = *lenp;
256         int     *id = *idp;
257
258         do {
259                 id0 = parsenum(&cp);
260                 if (*cp == '-') {
261                         cp++;
262                         id1 = parsenum(&cp);
263                 } else {
264                         id1 = id0;
265                 }
266                 if (id0 == -1 || id1 == -1) {
267                         syntaxerr("uid/gid -1 not permitted");
268                         return 0;
269                 }
270                 if ((len % 8) == 0)
271                         id = (int *) xrealloc(id, (len + 9) * sizeof(*id));
272                 id[len++] = id0;
273                 id[len++] = id1;
274                 if (!*cp)
275                         break;
276                 if (*cp != ',') {
277                         syntaxerr("bad uid/gid list");
278                         return 0;
279                 }
280                 cp++;
281         } while(1);
282
283         id[len] = -1;
284         *lenp = len;
285         *idp = id;
286         return 1;
287 }
288
289 static int
290 parsenum(char **cpp)
291 {
292         char    *cp = *cpp, c;
293         int     num = 0;
294
295         if (**cpp == '-')
296                 (*cpp)++;
297         while (isdigit(**cpp))
298                 (*cpp)++;
299         c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c;
300         return num;
301 }
302
303 static int
304 gettag(char *tag, int len)
305 {
306         xskip(cfp, " \t\n");
307         return xgettok(cfp, ':', tag, len);
308 }
309
310 static int
311 getattr(char *attr, int alen, char *value, int vlen)
312 {
313         int     ok;
314
315         xskip(cfp, " \t");
316         if ((ok = xgettok(cfp, '=', attr, alen)) < 0)
317                 syntaxerr("missing attribute");
318         if (ok <= 0)
319                 return ok;
320         xskip(cfp, " \t=");
321
322         return xgettok(cfp, 0, value, vlen);
323 }
324
325 static void
326 syntaxerr(char *msg)
327 {
328         xlog(L_ERROR, "%s:%d: syntax error: %s",
329                         cfname, cfp->x_line, msg);
330 }
331