"Fossies" - the Fresh Open Source Software Archive

Member "nfs-utils-2.5.3/support/export/auth.c" (20 Feb 2021, 7114 Bytes) of package /linux/misc/nfs-utils-2.5.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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/types.h>
   14 #include <sys/stat.h>
   15 #include <netinet/in.h>
   16 #include <arpa/inet.h>
   17 #include <errno.h>
   18 #include <fcntl.h>
   19 #include <unistd.h>
   20 
   21 #include "sockaddr.h"
   22 #include "misc.h"
   23 #include "nfslib.h"
   24 #include "exportfs.h"
   25 #include "export.h"
   26 #include "v4root.h"
   27 
   28 enum auth_error
   29 {
   30   bad_path,
   31   unknown_host,
   32   no_entry,
   33   not_exported,
   34   illegal_port,
   35   success
   36 };
   37 
   38 static void     auth_fixpath(char *path);
   39 static nfs_export my_exp;
   40 static nfs_client my_client;
   41 
   42 extern int use_ipaddr;
   43 
   44 extern struct state_paths etab;
   45 
   46 /*
   47 void
   48 auth_init(void)
   49 {
   50     auth_reload();
   51 }
   52 */
   53 
   54 /*
   55  * A client can match many different netgroups and it's tough to know
   56  * beforehand whether it will. If the concatenated string of netgroup
   57  * m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This
   58  * makes mountd change how it matches a client ip address when a mount
   59  * request comes in. It's more efficient at handling netgroups at the
   60  * expense of larger kernel caches.
   61  */
   62 static void
   63 check_useipaddr(void)
   64 {
   65     nfs_client *clp;
   66     int old_use_ipaddr = use_ipaddr;
   67     unsigned int len = 0;
   68 
   69     /* add length of m_hostname + 1 for the comma */
   70     for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
   71         len += (strlen(clp->m_hostname) + 1);
   72 
   73     if (len > (NFSCLNT_IDMAX / 2))
   74         use_ipaddr = 1;
   75     else
   76         use_ipaddr = 0;
   77 
   78     if (use_ipaddr != old_use_ipaddr)
   79         cache_flush(1);
   80 }
   81 
   82 unsigned int
   83 auth_reload()
   84 {
   85     struct stat     stb;
   86     static ino_t        last_inode;
   87     static int      last_fd = -1;
   88     static unsigned int counter;
   89     int         fd;
   90 
   91     if ((fd = open(etab.statefn, O_RDONLY)) < 0) {
   92         xlog(L_FATAL, "couldn't open %s", etab.statefn);
   93     } else if (fstat(fd, &stb) < 0) {
   94         xlog(L_FATAL, "couldn't stat %s", etab.statefn);
   95         close(fd);
   96     } else if (last_fd != -1 && stb.st_ino == last_inode) {
   97         /* We opened the etab file before, and its inode
   98          * number hasn't changed since then.
   99          */
  100         close(fd);
  101         return counter;
  102     } else {
  103         /* Need to process entries from the etab file.  Close
  104          * the file descriptor from the previous open (last_fd),
  105          * and keep the current file descriptor open to prevent
  106          * the file system reusing the current inode number
  107          * (last_inode).
  108          */
  109         if (last_fd != -1)
  110             close(last_fd);
  111         last_fd = fd;
  112         last_inode = stb.st_ino;
  113     }
  114 
  115     export_freeall();
  116     memset(&my_client, 0, sizeof(my_client));
  117     xtab_export_read();
  118     check_useipaddr();
  119     v4root_set();
  120 
  121     ++counter;
  122 
  123     return counter;
  124 }
  125 
  126 static char *get_client_ipaddr_name(const struct sockaddr *caller)
  127 {
  128     char buf[INET6_ADDRSTRLEN + 1];
  129 
  130     buf[0] = '$';
  131     host_ntop(caller, buf + 1, sizeof(buf) - 1);
  132     return strdup(buf);
  133 }
  134 
  135 static char *
  136 get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
  137         enum auth_error *error)
  138 {
  139     char *n;
  140 
  141     if (use_ipaddr)
  142         return get_client_ipaddr_name(caller);
  143     n = client_compose(ai);
  144     *error = unknown_host;
  145     if (!n)
  146         return NULL;
  147     if (*n)
  148         return n;
  149     free(n);
  150     return strdup("DEFAULT");
  151 }
  152 
  153 bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai)
  154 {
  155     return client_check(exp->m_client, ai);
  156 }
  157 
  158 bool namelist_client_matches(nfs_export *exp, char *dom)
  159 {
  160     return client_member(dom, exp->m_client->m_hostname);
  161 }
  162 
  163 bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
  164 {
  165     if (is_ipaddr_client(dom))
  166         return ipaddr_client_matches(exp, ai);
  167     return namelist_client_matches(exp, dom);
  168 }
  169 
  170 /* return static nfs_export with details filled in */
  171 static nfs_export *
  172 auth_authenticate_newcache(const struct sockaddr *caller,
  173                const char *path, struct addrinfo *ai,
  174                enum auth_error *error)
  175 {
  176     nfs_export *exp;
  177     int i;
  178 
  179     free(my_client.m_hostname);
  180 
  181     my_client.m_hostname = get_client_hostname(caller, ai, error);
  182     if (my_client.m_hostname == NULL)
  183         return NULL;
  184 
  185     my_client.m_naddr = 1;
  186     set_addrlist(&my_client, 0, caller);
  187     my_exp.m_client = &my_client;
  188 
  189     exp = NULL;
  190     for (i = 0; !exp && i < MCL_MAXTYPES; i++)
  191         for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
  192             if (strcmp(path, exp->m_export.e_path))
  193                 continue;
  194             if (!client_matches(exp, my_client.m_hostname, ai))
  195                 continue;
  196             if (exp->m_export.e_flags & NFSEXP_V4ROOT)
  197                 /* not acceptable for v[23] export */
  198                 continue;
  199             break;
  200         }
  201     *error = not_exported;
  202     if (!exp)
  203         return NULL;
  204 
  205     my_exp.m_export = exp->m_export;
  206     exp = &my_exp;
  207     return exp;
  208 }
  209 
  210 static nfs_export *
  211 auth_authenticate_internal(const struct sockaddr *caller, const char *path,
  212         struct addrinfo *ai, enum auth_error *error)
  213 {
  214     nfs_export *exp;
  215 
  216     exp = auth_authenticate_newcache(caller, path, ai, error);
  217     if (!exp)
  218         return NULL;
  219     if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
  220              nfs_get_port(caller) >= IPPORT_RESERVED) {
  221         *error = illegal_port;
  222         return NULL;
  223     }
  224     *error = success;
  225 
  226     return exp;
  227 }
  228 
  229 nfs_export *
  230 auth_authenticate(const char *what, const struct sockaddr *caller,
  231         const char *path)
  232 {
  233     nfs_export  *exp = NULL;
  234     char        epath[MAXPATHLEN+1];
  235     char        *p = NULL;
  236     char        buf[INET6_ADDRSTRLEN];
  237     struct addrinfo *ai = NULL;
  238     enum auth_error error = bad_path;
  239 
  240     if (path[0] != '/') {
  241         xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
  242                  what, host_ntop(caller, buf, sizeof(buf)), path);
  243         return exp;
  244     }
  245 
  246     strncpy(epath, path, sizeof (epath) - 1);
  247     epath[sizeof (epath) - 1] = '\0';
  248     auth_fixpath(epath); /* strip duplicate '/' etc */
  249 
  250     ai = client_resolve(caller);
  251     if (ai == NULL)
  252         return exp;
  253 
  254     /* Try the longest matching exported pathname. */
  255     while (1) {
  256         exp = auth_authenticate_internal(caller, epath, ai, &error);
  257         if (exp || (error != not_exported && error != no_entry))
  258             break;
  259         /* We have to treat the root, "/", specially. */
  260         if (p == &epath[1]) break;
  261         p = strrchr(epath, '/');
  262         if (p == epath) p++;
  263         *p = '\0';
  264     }
  265 
  266     host_ntop(caller, buf, sizeof(buf));
  267     switch (error) {
  268     case bad_path:
  269         xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
  270              what, buf, path);
  271         break;
  272 
  273     case unknown_host:
  274         xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
  275              what, buf, path, epath);
  276         break;
  277 
  278     case no_entry:
  279         xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
  280              what, buf, path, epath);
  281         break;
  282 
  283     case not_exported:
  284         xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
  285              what, buf, path, epath);
  286         break;
  287 
  288     case illegal_port:
  289         xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
  290              what, buf, path, epath, nfs_get_port(caller));
  291         break;
  292 
  293     case success:
  294         xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
  295              what, buf, nfs_get_port(caller), path, epath);
  296         break;
  297     default:
  298         xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
  299              what, buf, nfs_get_port(caller), path, epath, error);
  300     }
  301 
  302     nfs_freeaddrinfo(ai);
  303     return exp;
  304 }
  305 
  306 static void
  307 auth_fixpath(char *path)
  308 {
  309     char    *sp, *cp;
  310 
  311     for (sp = cp = path; *sp; sp++) {
  312         if (*sp != '/' || sp[1] != '/')
  313             *cp++ = *sp;
  314     }
  315     while (cp > path+1 && cp[-1] == '/')
  316         cp--;
  317     *cp = '\0';
  318 }