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