Initial revision
[nfs-utils.git] / utils / mountd / auth.c
1 /*
2  * utils/mountd/auth.c
3  *
4  * Authentication procedures for mountd.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include "config.h"
10
11 #include <sys/stat.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <errno.h>
15 #include "misc.h"
16 #include "nfslib.h"
17 #include "exportfs.h"
18 #include "mountd.h"
19
20 enum auth_error
21 {
22   bad_path,
23   unknown_host,
24   no_entry,
25   not_exported,
26   illegal_port,
27   faked_hostent,
28   success
29 };
30
31 static void             auth_fixpath(char *path);
32 static nfs_export*      auth_authenticate_internal
33   (char *what, struct sockaddr_in *caller, char *path,
34    struct hostent **hpp, enum auth_error *error);
35 static char     *export_file = NULL;
36
37 void
38 auth_init(char *exports)
39 {
40
41         export_file = exports;
42         auth_reload();
43         xtab_mount_write();
44 }
45
46 int
47 auth_reload()
48 {
49         struct stat             stb;
50         static time_t           last_modified = 0;
51
52         if (stat(_PATH_ETAB, &stb) < 0)
53                 xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
54         if (stb.st_mtime == last_modified)
55                 return 0;
56         last_modified = stb.st_mtime;
57
58         export_freeall();
59         // export_read(export_file);
60         xtab_export_read();
61
62         return 1;
63 }
64
65 static nfs_export *
66 auth_authenticate_internal(char *what, struct sockaddr_in *caller,
67                            char *path, struct hostent **hpp,
68                            enum auth_error *error)
69 {
70         struct in_addr          addr = caller->sin_addr;
71         nfs_export              *exp;
72
73         if (path[0] != '/') {
74                 *error = bad_path;
75                 return NULL;
76         }
77         auth_fixpath(path);
78
79         if (!(*hpp = gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET)))
80                 *hpp = get_hostent((const char *)&addr, sizeof(addr),
81                                    AF_INET);
82         else {
83                 /* must make sure the hostent is authorative. */
84                 char *name = strdup((*hpp)->h_name);
85                 char **sp;
86                 *hpp = gethostbyname(name);
87                 /* now make sure the "addr" is in the list */
88                 for (sp = (*hpp)->h_addr_list ; *sp ; sp++) {
89                         if (memcmp(*sp, &addr, (*hpp)->h_length)==0)
90                                 break;
91                 }
92                 
93                 if (!*sp) {
94                         free(name);
95                         /* it was a FAKE */
96                         *error = faked_hostent;
97                         *hpp = NULL;
98                         return NULL;
99                 }
100                 *hpp = hostent_dup (*hpp);
101                 free(name);
102         }
103
104         if (!(exp = export_find(*hpp, path))) {
105                 *error = no_entry;
106                 return NULL;
107         }
108         if (!exp->m_mayexport) {
109                 *error = not_exported;
110                 return NULL;
111         }
112
113         if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
114             (ntohs(caller->sin_port) <  IPPORT_RESERVED/2 ||
115              ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
116                 *error = illegal_port;
117                 return NULL;
118         }
119
120         *error = success;
121
122         return exp;
123 }
124
125 nfs_export *
126 auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
127 {
128         nfs_export      *exp = NULL;
129         char            epath[MAXPATHLEN+1];
130         char            *p = NULL;
131         struct hostent  *hp = NULL;
132         struct in_addr  addr = caller->sin_addr;
133         enum auth_error error;
134
135         if (path [0] != '/') return exp;
136
137         strncpy(epath, path, sizeof (epath) - 1);
138         epath[sizeof (epath) - 1] = '\0';
139
140         /* Try the longest matching exported pathname. */
141         while (1) {
142                 if (hp) {
143                         free (hp);
144                         hp = NULL;
145                 }
146                 exp = auth_authenticate_internal(what, caller, epath,
147                                                  &hp, &error);
148                 if (exp || (error != not_exported && error != no_entry))
149                         break;
150                 /* We have to treat the root, "/", specially. */
151                 if (p == &epath[1]) break;
152                 p = strrchr(epath, '/');
153                 if (p == epath) p++;
154                 *p = '\0';
155         }
156
157         switch (error) {
158         case bad_path:
159                 xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
160                      what, inet_ntoa(addr), path);
161                 break;
162
163         case unknown_host:
164                 xlog(L_WARNING, "%s request from unknown host %s for %s (%s)",
165                      what, inet_ntoa(addr), path, epath);
166                 break;
167
168         case no_entry:
169                 xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
170                      what, hp->h_name, path, epath);
171                 break;
172
173         case not_exported:
174                 xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
175                      what, hp->h_name, path, epath);
176                 break;
177
178         case illegal_port:
179                 xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d",
180                      what, hp->h_name, path, epath, ntohs(caller->sin_port));
181                 break;
182
183         case faked_hostent:
184                 xlog(L_WARNING, "refused %s request from %s for %s (%s): faked hostent",
185                      what, inet_ntoa(addr), path, epath);
186                 break;
187
188         case success:
189                 xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
190                      what, hp->h_name, ntohs(caller->sin_port), path, epath);
191                 break;
192         default:
193                 xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d",
194                      what, hp->h_name, ntohs(caller->sin_port), path, epath, error);
195         }
196
197         if (hp)
198                 free (hp);
199
200         return exp;
201 }
202
203 static void
204 auth_fixpath(char *path)
205 {
206         char    *sp, *cp;
207
208         for (sp = cp = path; *sp; sp++) {
209                 if (*sp != '/' || sp[1] != '/')
210                         *cp++ = *sp;
211         }
212         while (cp > path+1 && cp[-1] == '/')
213                 cp--;
214         *cp = '\0';
215 }