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