* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <unistd.h>
#include "misc.h"
#include "nfslib.h"
#include "exportfs.h"
no_entry,
not_exported,
illegal_port,
- faked_hostent,
- no_forward_dns,
success
};
static void auth_fixpath(char *path);
-static nfs_export* auth_authenticate_internal
- (char *what, struct sockaddr_in *caller, char *path,
- struct hostent **hpp, enum auth_error *error);
static char *export_file = NULL;
+static nfs_export my_exp;
+static nfs_client my_client;
+
+extern int new_cache;
+extern int use_ipaddr;
void
auth_init(char *exports)
xtab_mount_write();
}
-int
+/*
+ * A client can match many different netgroups and it's tough to know
+ * beforehand whether it will. If the concatenated string of netgroup
+ * m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This
+ * makes mountd change how it matches a client ip address when a mount
+ * request comes in. It's more efficient at handling netgroups at the
+ * expense of larger kernel caches.
+ */
+static void
+check_useipaddr(void)
+{
+ nfs_client *clp;
+ int old_use_ipaddr = use_ipaddr;
+ unsigned int len = 0;
+
+ /* add length of m_hostname + 1 for the comma */
+ for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
+ len += (strlen(clp->m_hostname) + 1);
+
+ if (len > (NFSCLNT_IDMAX / 2))
+ use_ipaddr = 1;
+ else
+ use_ipaddr = 0;
+
+ if (use_ipaddr != old_use_ipaddr)
+ cache_flush(1);
+}
+
+unsigned int
auth_reload()
{
struct stat stb;
- static time_t last_modified = 0;
-
- if (stat(_PATH_ETAB, &stb) < 0)
+ static ino_t last_inode;
+ static int last_fd;
+ static unsigned int counter;
+ int fd;
+
+ if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) {
+ xlog(L_FATAL, "couldn't open %s", _PATH_ETAB);
+ } else if (fstat(fd, &stb) < 0) {
xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
- if (stb.st_mtime == last_modified)
- return 0;
- last_modified = stb.st_mtime;
+ } else if (stb.st_ino == last_inode) {
+ close(fd);
+ return counter;
+ } else {
+ close(last_fd);
+ last_fd = fd;
+ last_inode = stb.st_ino;
+ }
export_freeall();
- // export_read(export_file);
+ memset(&my_client, 0, sizeof(my_client));
xtab_export_read();
+ check_useipaddr();
+ ++counter;
- return 1;
+ return counter;
}
static nfs_export *
auth_authenticate_internal(char *what, struct sockaddr_in *caller,
- char *path, struct hostent **hpp,
+ char *path, struct hostent *hp,
enum auth_error *error)
{
- struct in_addr addr = caller->sin_addr;
nfs_export *exp;
- if (path[0] != '/') {
- *error = bad_path;
- return NULL;
- }
- auth_fixpath(path);
-
- if (!(*hpp = gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET)))
- *hpp = get_hostent((const char *)&addr, sizeof(addr),
- AF_INET);
- else {
- /* must make sure the hostent is authorative. */
- char **sp;
- struct hostent *forward = NULL;
- char *tmpname;
-
- *hpp = hostent_dup (*hpp);
- tmpname = xstrdup((*hpp)->h_name);
- if (tmpname) {
- forward = gethostbyname(tmpname);
- free(tmpname);
- }
- if (forward) {
- /* now make sure the "addr" is in the list */
- for (sp = forward->h_addr_list ; *sp ; sp++) {
- if (memcmp(*sp, &addr, forward->h_length)==0)
- break;
+ if (new_cache) {
+ int i;
+ /* return static nfs_export with details filled in */
+ char *n;
+ free(my_client.m_hostname);
+ if (use_ipaddr) {
+ my_client.m_hostname =
+ strdup(inet_ntoa(caller->sin_addr));
+ } else {
+ n = client_compose(hp);
+ *error = unknown_host;
+ if (!n)
+ my_client.m_hostname = NULL;
+ else if (*n)
+ my_client.m_hostname = n;
+ else {
+ free(n);
+ my_client.m_hostname = strdup("DEFAULT");
}
-
- if (!*sp) {
- /* it was a FAKE */
- *error = faked_hostent;
- return NULL;
+ }
+ if (my_client.m_hostname == NULL)
+ return NULL;
+ my_client.m_naddr = 1;
+ my_client.m_addrlist[0] = caller->sin_addr;
+ my_exp.m_client = &my_client;
+
+ exp = NULL;
+ for (i = 0; !exp && i < MCL_MAXTYPES; i++)
+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+ if (strcmp(path, exp->m_export.e_path))
+ continue;
+ if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
+ continue;
+ if (use_ipaddr && !client_check(exp->m_client, hp))
+ continue;
+ break;
}
- free (*hpp);
- *hpp = hostent_dup (forward);
+ *error = not_exported;
+ if (!exp)
+ return exp;
+
+ my_exp.m_export = exp->m_export;
+ exp = &my_exp;
+
+ } else {
+ if (!(exp = export_find(hp, path))) {
+ *error = no_entry;
+ return NULL;
}
- else {
- /* never heard of it. misconfigured DNS? */
- *error = no_forward_dns;
+ if (!exp->m_mayexport) {
+ *error = not_exported;
return NULL;
}
}
-
- if (!(exp = export_find(*hpp, path))) {
- *error = no_entry;
- return NULL;
- }
- if (!exp->m_mayexport) {
- *error = not_exported;
- return NULL;
- }
-
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
- (ntohs(caller->sin_port) < IPPORT_RESERVED/2 ||
- ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
+ (ntohs(caller->sin_port) < IPPORT_RESERVED/2 ||
+ ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
*error = illegal_port;
return NULL;
}
-
*error = success;
return exp;
char *p = NULL;
struct hostent *hp = NULL;
struct in_addr addr = caller->sin_addr;
- enum auth_error error;
+ enum auth_error error = bad_path;
if (path [0] != '/') {
xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
strncpy(epath, path, sizeof (epath) - 1);
epath[sizeof (epath) - 1] = '\0';
+ auth_fixpath(epath); /* strip duplicate '/' etc */
+
+ hp = client_resolve(caller->sin_addr);
+ if (!hp)
+ return exp;
/* Try the longest matching exported pathname. */
while (1) {
- if (hp) {
- free (hp);
- hp = NULL;
- }
exp = auth_authenticate_internal(what, caller, epath,
- &hp, &error);
+ hp, &error);
if (exp || (error != not_exported && error != no_entry))
break;
/* We have to treat the root, "/", specially. */
break;
case unknown_host:
- xlog(L_WARNING, "%s request from unknown host %s for %s (%s)",
+ xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
what, inet_ntoa(addr), path, epath);
break;
what, hp->h_name, path, epath, ntohs(caller->sin_port));
break;
- case faked_hostent:
- xlog(L_WARNING, "refused %s request from %s (%s) for %s (%s): DNS forward lookup does't match with reverse",
- what, inet_ntoa(addr), hp->h_name, path, epath);
- break;
-
- case no_forward_dns:
- xlog(L_WARNING, "refused %s request from %s (%s) for %s (%s): no DNS forward lookup",
- what, inet_ntoa(addr), hp->h_name, path, epath);
- break;
-
case success:
xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
what, hp->h_name, ntohs(caller->sin_port), path, epath);