]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mountd/auth.c
Understand type 2 and type 3 filesystem identifiers.
[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 #include "xmalloc.h"
20
21 enum auth_error
22 {
23   bad_path,
24   unknown_host,
25   no_entry,
26   not_exported,
27   illegal_port,
28   success
29 };
30
31 static void             auth_fixpath(char *path);
32 static char     *export_file = NULL;
33 static nfs_export my_exp;
34 static nfs_client my_client;
35
36 extern int new_cache;
37
38 void
39 auth_init(char *exports)
40 {
41
42         export_file = exports;
43         auth_reload();
44         xtab_mount_write();
45 }
46
47 int
48 auth_reload()
49 {
50         struct stat             stb;
51         static time_t           last_modified = 0;
52
53         if (stat(_PATH_ETAB, &stb) < 0)
54                 xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
55         if (stb.st_mtime == last_modified)
56                 return 0;
57         last_modified = stb.st_mtime;
58
59         export_freeall();
60         memset(&my_client, 0, sizeof(my_client));
61         // export_read(export_file);
62         xtab_export_read();
63
64         return 1;
65 }
66
67 static nfs_export *
68 auth_authenticate_internal(char *what, struct sockaddr_in *caller,
69                            char *path, struct hostent *hp,
70                            enum auth_error *error)
71 {
72         nfs_export              *exp;
73
74         if (new_cache) {
75                 int i;
76                 /* return static nfs_export with details filled in */
77                 if (my_client.m_naddr != 1 ||
78                     my_client.m_addrlist[0].s_addr != caller->sin_addr.s_addr) {
79                         /* different client to last time, so do a lookup */
80                         char *n;
81                         my_client.m_naddr = 0;
82                         my_client.m_addrlist[0] = caller->sin_addr;
83                         n = client_compose(caller->sin_addr);
84                         *error = unknown_host;
85                         if (!n)
86                                 return NULL;
87                         strcpy(my_client.m_hostname, *n?n:"DEFAULT");
88                         free(n);
89                         my_client.m_naddr = 1;
90                 }
91
92                 my_exp.m_client = &my_client;
93
94                 exp = NULL;
95                 for (i = 0; !exp && i < MCL_MAXTYPES; i++) 
96                         for (exp = exportlist[i]; exp; exp = exp->m_next) {
97                                 if (!client_member(my_client.m_hostname, exp->m_client->m_hostname))
98                                         continue;
99                                 if (strcmp(path, exp->m_export.e_path))
100                                         continue;
101                                 break;
102                         }
103                 *error = not_exported;
104                 if (!exp)
105                         return exp;
106
107                 my_exp.m_export = exp->m_export;
108                 exp = &my_exp;
109
110         } else {
111                 if (!(exp = export_find(hp, path))) {
112                         *error = no_entry;
113                         return NULL;
114                 }
115                 if (!exp->m_mayexport) {
116                         *error = not_exported;
117                         return NULL;
118                 }
119         }
120         if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
121                     (ntohs(caller->sin_port) <  IPPORT_RESERVED/2 ||
122                      ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
123                 *error = illegal_port;
124                 return NULL;
125         }
126         *error = success;
127
128         return exp;
129 }
130
131 nfs_export *
132 auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
133 {
134         nfs_export      *exp = NULL;
135         char            epath[MAXPATHLEN+1];
136         char            *p = NULL;
137         struct hostent  *hp = NULL;
138         struct in_addr  addr = caller->sin_addr;
139         enum auth_error error;
140
141         if (path [0] != '/') {
142                 xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
143                      what, inet_ntoa(addr), path);
144                 return exp;
145         }
146
147         strncpy(epath, path, sizeof (epath) - 1);
148         epath[sizeof (epath) - 1] = '\0';
149         auth_fixpath(epath); /* strip duplicate '/' etc */
150
151         hp = get_reliable_hostbyaddr((const char*)&caller->sin_addr, sizeof(struct in_addr),
152                                      AF_INET);
153         if (!hp)
154                 hp = get_hostent((const char*)&caller->sin_addr, sizeof(struct in_addr),
155                                      AF_INET);
156         if (!hp)
157                 return exp;
158
159         /* Try the longest matching exported pathname. */
160         while (1) {
161                 exp = auth_authenticate_internal(what, caller, epath,
162                                                  hp, &error);
163                 if (exp || (error != not_exported && error != no_entry))
164                         break;
165                 /* We have to treat the root, "/", specially. */
166                 if (p == &epath[1]) break;
167                 p = strrchr(epath, '/');
168                 if (p == epath) p++;
169                 *p = '\0';
170         }
171
172         switch (error) {
173         case bad_path:
174                 xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
175                      what, inet_ntoa(addr), path);
176                 break;
177
178         case unknown_host:
179                 xlog(L_WARNING, "%s request from unknown host %s for %s (%s)",
180                      what, inet_ntoa(addr), path, epath);
181                 break;
182
183         case no_entry:
184                 xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
185                      what, hp->h_name, path, epath);
186                 break;
187
188         case not_exported:
189                 xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
190                      what, hp->h_name, path, epath);
191                 break;
192
193         case illegal_port:
194                 xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d",
195                      what, hp->h_name, path, epath, ntohs(caller->sin_port));
196                 break;
197
198         case success:
199                 xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
200                      what, hp->h_name, ntohs(caller->sin_port), path, epath);
201                 break;
202         default:
203                 xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d",
204                      what, hp->h_name, ntohs(caller->sin_port), path, epath, error);
205         }
206
207         if (hp)
208                 free (hp);
209
210         return exp;
211 }
212
213 static void
214 auth_fixpath(char *path)
215 {
216         char    *sp, *cp;
217
218         for (sp = cp = path; *sp; sp++) {
219                 if (*sp != '/' || sp[1] != '/')
220                         *cp++ = *sp;
221         }
222         while (cp > path+1 && cp[-1] == '/')
223                 cp--;
224         *cp = '\0';
225 }