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