Logo Search packages:      
Sourcecode: unfs3 version File versions  Download package

mount.c

/*
 * UNFS3 mount protocol procedures
 * (C) 2004, Pascal Schmidt
 * see file LICENSE for license details
 */

#include "config.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <rpc/rpc.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

#include "nfs.h"
#include "mount.h"
#include "daemon.h"
#include "fh.h"
#include "fh_cache.h"
#include "fd_cache.h"
#include "Config/exports.h"
#include "password.h"
#include "backend.h"

#ifndef PATH_MAX
# define PATH_MAX 4096
#endif

#define IS_SECURE(port) ((port) < 1024)

/*
 * number of active mounts
 *
 * only a guess since clients can crash and/or not sent UMNT calls
 */
static int mount_cnt = 0;

/* list of currently mounted directories */
static mountlist mount_list = NULL;

static char nonce[32] = "";

/*
 * add entry to mount list
 */
static void add_mount(const char *path, struct svc_req *rqstp)
{
    mountlist new;
    mountlist iter;
    char *host;

    new = malloc(sizeof(struct mountbody));
    if (!new)
      return;

    host = inet_ntoa(get_remote(rqstp));
    new->ml_hostname = malloc(strlen(host) + 1);
    if (!new->ml_hostname) {
      free(new);
      return;
    }

    new->ml_directory = malloc(strlen(path) + 1);
    if (!new->ml_directory) {
      free(new->ml_hostname);
      free(new);
      return;
    }

    /* initialize the new entry */
    new->ml_next = NULL;
    strcpy(new->ml_hostname, host);
    strcpy(new->ml_directory, path);

    iter = mount_list;
    if (iter) {
      while (iter->ml_next)
          iter = iter->ml_next;
      iter->ml_next = new;
    } else
      mount_list = new;

    mount_cnt++;
}

/*
 * remove entries from mount list
 */
static void remove_mount(const char *path, struct svc_req *rqstp)
{
    mountlist iter, next, prev = NULL;
    char *host;

    host = inet_ntoa(get_remote(rqstp));

    iter = mount_list;
    while (iter) {
      if (strcmp(iter->ml_hostname, host) == 0 &&
          (!path || strcmp(iter->ml_directory, path) == 0)) {
          if (prev)
            prev->ml_next = iter->ml_next;
          else
            mount_list = iter->ml_next;

          next = iter->ml_next;

          free(iter->ml_hostname);
          free(iter->ml_directory);
          free(iter);

          iter = next;

          /* adjust mount count */
          if (mount_cnt > 0)
            mount_cnt--;
      } else {
          prev = iter;
          iter = iter->ml_next;
      }
    }
}

void *mountproc_null_3_svc(U(void *argp), U(struct svc_req *rqstp))
{
    static void *result = NULL;

    return &result;
}

mountres3 *mountproc_mnt_3_svc(dirpath * argp, struct svc_req * rqstp)
{
    char buf[PATH_MAX];
    static unfs3_fh_t fh;
    static mountres3 result;
    static int auth = AUTH_UNIX;
    int authenticated = 0;
    char *password;

    /* We need to modify the *argp pointer. Make a copy. */
    char *dpath = *argp;

    /* error out if not version 3 */
    if (rqstp->rq_vers != 3) {
      logmsg(LOG_INFO,
             "%s attempted mount with unsupported protocol version",
             inet_ntoa(get_remote(rqstp)));
      result.fhs_status = MNT3ERR_INVAL;
      return &result;
    }

    /* Check for "mount commands" */
    if (strncmp(dpath, "@getnonce", sizeof("@getnonce") - 1) == 0) {
      gen_nonce(nonce);
      result.fhs_status = MNT3_OK;
      result.mountres3_u.mountinfo.fhandle.fhandle3_len = 32;
      result.mountres3_u.mountinfo.fhandle.fhandle3_val = nonce;
      result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
      result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = &auth;
      return &result;
    } else if (strncmp(dpath, "@password:", sizeof("@password:") - 1) == 0) {
      char pw[PASSWORD_MAXLEN + 1];

      mnt_cmd_argument(&dpath, "@password:", pw, PASSWORD_MAXLEN);
      if (exports_options(dpath, rqstp, &password, NULL) != -1) {
          authenticated = !strcmp(password, pw);
      }
      /* else leave authenticated unchanged */
    } else if (strncmp(dpath, "@otp:", sizeof("@otp:") - 1) == 0) {
      /* The otp from the client */
      char otp[PASSWORD_MAXLEN + 1];

      /* Our calculated otp */
      unsigned char hexdigest[32];

      mnt_cmd_argument(&dpath, "@otp:", otp, PASSWORD_MAXLEN);
      if (exports_options(dpath, rqstp, &password, NULL) != -1) {
          otp_digest(nonce, password, hexdigest);

          /* Compare our calculated digest with what the client submitted */
          authenticated = !strncmp(hexdigest, otp, 32);

          /* Change nonce */
          gen_nonce(nonce);
      }
      /* else leave authenticated unchanged */
    }

    if ((exports_opts & OPT_REMOVABLE) && export_point(dpath)) {
      /* Removable media export point. Do not call realpath; simply copy
         path */
      strncpy(buf, dpath, PATH_MAX);
    } else if (!backend_realpath(dpath, buf)) {
      /* the given path does not exist */
      result.fhs_status = MNT3ERR_NOENT;
      return &result;
    }

    if (strlen(buf) + 1 > NFS_MAXPATHLEN) {
      logmsg(LOG_INFO, "%s attempted to mount jumbo path",
             inet_ntoa(get_remote(rqstp)));
      result.fhs_status = MNT3ERR_NAMETOOLONG;
      return &result;
    }

    if ((exports_options(buf, rqstp, &password, NULL) == -1)
      || (!authenticated && password[0])
      || (!IS_SECURE(ntohs(get_port(rqstp))))
       ) {
      /* not exported to this host or at all, or a password defined and not 
         authenticated */
      result.fhs_status = MNT3ERR_ACCES;
      return &result;
    }

    fh = fh_comp(buf, rqstp, FH_DIR);

    if (!fh_valid(fh)) {
      logmsg(LOG_INFO, "%s attempted to mount non-directory",
             inet_ntoa(get_remote(rqstp)));
      result.fhs_status = MNT3ERR_NOTDIR;
      return &result;
    }

    add_mount(dpath, rqstp);

    result.fhs_status = MNT3_OK;
    result.mountres3_u.mountinfo.fhandle.fhandle3_len = fh_length(&fh);
    result.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *) &fh;
    result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
    result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = &auth;

    return &result;
}

mountlist *mountproc_dump_3_svc(U(void *argp), U(struct svc_req *rqstp))
{
    return &mount_list;
}

void *mountproc_umnt_3_svc(dirpath * argp, struct svc_req *rqstp)
{
    /* RPC times out if we use a NULL pointer */
    static void *result = NULL;

    remove_mount(*argp, rqstp);

    /* if no more mounts are active, flush all open file descriptors */
    if (mount_cnt == 0)
      fd_cache_purge();

    return &result;
}

void *mountproc_umntall_3_svc(U(void *argp), struct svc_req *rqstp)
{
    /* RPC times out if we use a NULL pointer */
    static void *result = NULL;

    remove_mount(NULL, rqstp);

    /* if no more mounts are active, flush all open file descriptors */
    if (mount_cnt == 0)
      fd_cache_purge();

    return &result;
}

exports *mountproc_export_3_svc(U(void *argp), U(struct svc_req *rqstp))
{
    return &exports_nfslist;
}

Generated by  Doxygen 1.6.0   Back to index