4 * Authentication procedures for mountd.
6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
13 #include <sys/types.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
38 static void auth_fixpath(char *path);
39 static char *export_file = NULL;
40 static nfs_export my_exp;
41 static nfs_client my_client;
44 extern int use_ipaddr;
47 auth_init(char *exports)
50 export_file = exports;
56 * A client can match many different netgroups and it's tough to know
57 * beforehand whether it will. If the concatenated string of netgroup
58 * m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This
59 * makes mountd change how it matches a client ip address when a mount
60 * request comes in. It's more efficient at handling netgroups at the
61 * expense of larger kernel caches.
67 int old_use_ipaddr = use_ipaddr;
70 /* add length of m_hostname + 1 for the comma */
71 for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
72 len += (strlen(clp->m_hostname) + 1);
74 if (len > (NFSCLNT_IDMAX / 2))
79 if (use_ipaddr != old_use_ipaddr)
87 static ino_t last_inode;
89 static unsigned int counter;
92 if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) {
93 xlog(L_FATAL, "couldn't open %s", _PATH_ETAB);
94 } else if (fstat(fd, &stb) < 0) {
95 xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
96 } else if (stb.st_ino == last_inode) {
102 last_inode = stb.st_ino;
106 memset(&my_client, 0, sizeof(my_client));
116 static char *get_client_ipaddr_name(const struct sockaddr *caller)
118 char buf[INET6_ADDRSTRLEN + 1];
121 host_ntop(caller, buf + 1, sizeof(buf) - 1);
126 get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
127 enum auth_error *error)
132 return get_client_ipaddr_name(caller);
133 n = client_compose(ai);
134 *error = unknown_host;
140 return strdup("DEFAULT");
143 bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai)
145 return client_check(exp->m_client, ai);
148 bool namelist_client_matches(nfs_export *exp, char *dom)
150 return client_member(dom, exp->m_client->m_hostname);
153 bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
155 if (is_ipaddr_client(dom))
156 return ipaddr_client_matches(exp, ai);
157 return namelist_client_matches(exp, dom);
160 /* return static nfs_export with details filled in */
162 auth_authenticate_newcache(const struct sockaddr *caller,
163 const char *path, struct addrinfo *ai,
164 enum auth_error *error)
169 free(my_client.m_hostname);
171 my_client.m_hostname = get_client_hostname(caller, ai, error);
172 if (my_client.m_hostname == NULL)
175 my_client.m_naddr = 1;
176 set_addrlist(&my_client, 0, caller);
177 my_exp.m_client = &my_client;
180 for (i = 0; !exp && i < MCL_MAXTYPES; i++)
181 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
182 if (strcmp(path, exp->m_export.e_path))
184 if (!client_matches(exp, my_client.m_hostname, ai))
186 if (exp->m_export.e_flags & NFSEXP_V4ROOT)
187 /* not acceptable for v[23] export */
191 *error = not_exported;
195 my_exp.m_export = exp->m_export;
201 auth_authenticate_internal(const struct sockaddr *caller, const char *path,
202 struct addrinfo *ai, enum auth_error *error)
207 exp = auth_authenticate_newcache(caller, path, ai, error);
211 exp = export_find(ai, path);
217 if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
218 nfs_get_port(caller) >= IPPORT_RESERVED) {
219 *error = illegal_port;
228 auth_authenticate(const char *what, const struct sockaddr *caller,
231 nfs_export *exp = NULL;
232 char epath[MAXPATHLEN+1];
234 char buf[INET6_ADDRSTRLEN];
235 struct addrinfo *ai = NULL;
236 enum auth_error error = bad_path;
238 if (path[0] != '/') {
239 xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
240 what, host_ntop(caller, buf, sizeof(buf)), path);
244 strncpy(epath, path, sizeof (epath) - 1);
245 epath[sizeof (epath) - 1] = '\0';
246 auth_fixpath(epath); /* strip duplicate '/' etc */
248 ai = client_resolve(caller);
252 /* Try the longest matching exported pathname. */
254 exp = auth_authenticate_internal(caller, epath, ai, &error);
255 if (exp || (error != not_exported && error != no_entry))
257 /* We have to treat the root, "/", specially. */
258 if (p == &epath[1]) break;
259 p = strrchr(epath, '/');
266 xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
267 what, host_ntop(caller, buf, sizeof(buf)), path);
271 xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
272 what, host_ntop(caller, buf, sizeof(buf)), path, epath);
276 xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
277 what, ai->ai_canonname, path, epath);
281 xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
282 what, ai->ai_canonname, path, epath);
286 xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
287 what, ai->ai_canonname, path, epath, nfs_get_port(caller));
291 xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
292 what, ai->ai_canonname, nfs_get_port(caller), path, epath);
295 xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
296 what, ai->ai_canonname, nfs_get_port(caller),
305 auth_fixpath(char *path)
309 for (sp = cp = path; *sp; sp++) {
310 if (*sp != '/' || sp[1] != '/')
313 while (cp > path+1 && cp[-1] == '/')