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