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

main.c

/*
 * nfsmount/main.c
 */
/* ----------------------------------------------------------------------- *
 *   
 *   Copyright 2004 H. Peter Anvin - All Rights Reserved
 *
 *   Permission is hereby granted, free of charge, to any person
 *   obtaining a copy of this software and associated documentation
 *   files (the "Software"), to deal in the Software without
 *   restriction, including without limitation the rights to use,
 *   copy, modify, merge, publish, distribute, sublicense, and/or
 *   sell copies of the Software, and to permit persons to whom
 *   the Software is furnished to do so, subject to the following
 *   conditions:
 *   
 *   The above copyright notice and this permission notice shall
 *   be included in all copies or substantial portions of the Software.
 *   
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 *
 * ----------------------------------------------------------------------- */


#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>

#include "nfsmount.h"
#include "sunrpc.h"
#include "dummypmap.h"

static char *progname;

static struct nfs_mount_data mount_data = {
      .version = NFS_MOUNT_VERSION,
      .flags = NFS_MOUNT_NONLM | NFS_MOUNT_VER3 | NFS_MOUNT_TCP,
      .rsize = 0,       /* Server's choice */
      .wsize = 0,       /* Server's choice */
      .timeo = 7,
      .retrans = 3,
      .acregmin = 3,
      .acregmax = 60,
      .acdirmin = 30,
      .acdirmax = 60,
      .namlen = NAME_MAX,
};

__u32 nfs_port;

static struct int_opts {
      char *name;
      int  *val;
} int_opts[] = {
      { "port",   &nfs_port },
      { "rsize",  &mount_data.rsize },
      { "wsize",  &mount_data.wsize },
      { "timeo",  &mount_data.timeo },
      { "retrans",      &mount_data.retrans },
      { "acregmin",     &mount_data.acregmin },
      { "acregmax",     &mount_data.acregmax },
      { "acdirmin",     &mount_data.acdirmin },
      { "acdirmax",     &mount_data.acdirmax },
      { NULL,           NULL }
};

static struct bool_opts {
      char *name;
      int  and_mask;
      int  or_mask;
} bool_opts[] = {
      { "soft",   ~NFS_MOUNT_SOFT,  NFS_MOUNT_SOFT },
      { "hard",   ~NFS_MOUNT_SOFT,  0 },
      { "intr",   ~NFS_MOUNT_INTR,  NFS_MOUNT_INTR },
      { "nointr", ~NFS_MOUNT_INTR,  0 },
      { "posix",  ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX },
      { "noposix",      ~NFS_MOUNT_POSIX, 0 },
      { "cto",    ~NFS_MOUNT_NOCTO, 0 },
      { "nocto",  ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO },
      { "ac",           ~NFS_MOUNT_NOAC,  0 },
      { "noac",   ~NFS_MOUNT_NOAC,  NFS_MOUNT_NOAC },
      { "lock",   ~NFS_MOUNT_NONLM, 0 },
      { "nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM },
      { "v2",           ~NFS_MOUNT_VER3,  0 },
      { "v3",           ~NFS_MOUNT_VER3,  NFS_MOUNT_VER3 },
      { "udp",    ~NFS_MOUNT_TCP,         0 },
      { "tcp",    ~NFS_MOUNT_TCP,         NFS_MOUNT_TCP },
      { "broken_suid",~NFS_MOUNT_BROKEN_SUID,   NFS_MOUNT_BROKEN_SUID },
      { "ro",           ~NFS_MOUNT_KLIBC_RONLY, NFS_MOUNT_KLIBC_RONLY },
      { "rw",           ~NFS_MOUNT_KLIBC_RONLY, 0 },
      { NULL,           0,                0 }
};

static int parse_int(const char *val, const char *ctx)
{
      char *end;
      int ret;

      ret = (int) strtoul(val, &end, 0);
      if (*val == '\0' || *end != '\0') {
            fprintf(stderr, "%s: invalid value for %s\n", val, ctx);
            exit(1);
      }
      return ret;
}

static void parse_opts(char *opts)
{
      char *cp, *val;

      while ((cp = strsep(&opts, ",")) != NULL) {
            if (*cp == '\0')
                  continue;
            if ((val = strchr(cp, '=')) != NULL) {
                  struct int_opts *opts = int_opts;
                  *val++ = '\0';
                  while (opts->name && strcmp(opts->name, cp) != 0)
                        opts++;
                  if (opts->name)
                        *(opts->val) = parse_int(val, opts->name);
                  else {
                        fprintf(stderr, "%s: bad option '%s'\n",
                              progname, cp);
                        exit(1);
                  }
            } else {
                  struct bool_opts *opts = bool_opts;
                  while (opts->name && strcmp(opts->name, cp) != 0)
                        opts++;
                  if (opts->name) {
                        mount_data.flags &= opts->and_mask;
                        mount_data.flags |= opts->or_mask;
                  } else {
                        fprintf(stderr, "%s: bad option '%s'\n",
                              progname, cp);
                        exit(1);
                  }
            }
      }
}

static __u32 parse_addr(const char *ip)
{
      struct in_addr in;
      if (inet_aton(ip, &in) == 0) {
            fprintf(stderr, "%s: can't parse IP address '%s'\n",
                  progname, ip);
            exit(1);
      }
      return in.s_addr;
}

static void check_path(const char *path)
{
      struct stat st;

      if (stat(path, &st) == -1) {
            perror("stat");
            exit(1);
      }
      else if (!S_ISDIR(st.st_mode)) {
            fprintf(stderr, "%s: '%s' not a directory\n",
                  progname, path);
            exit(1);
      }
}

int main(int argc, char *argv[])
      __attribute__ ((weak, alias ("nfsmount_main")));

int nfsmount_main(int argc, char *argv[])
{
      struct timeval now;
      __u32 server = 0;
      char *rem_name;
      char *rem_path;
      char *hostname;
      char *path;
      int c;
      int spoof_portmap = 0;
      FILE *portmap_file = NULL;

      progname = argv[0];

      gettimeofday(&now, NULL);
      srand48(now.tv_usec ^ (now.tv_sec << 24));

      while ((c = getopt(argc, argv, "o:p:")) != EOF) {
            switch (c) {
            case 'o':
                  parse_opts(optarg);
                  break;
            case 'p':
                  spoof_portmap = 1;
                  portmap_file  = fopen(optarg, "w");
                  break;
            case '?':
                  fprintf(stderr, "%s: invalid option -%c\n",
                        progname, optopt);
                  exit(1);
            }
      }

      if (optind == argc) {
            fprintf(stderr, "%s: need a path\n", progname);
            exit(1);
      }

      hostname = rem_path = argv[optind];

      if ((rem_name = strdup(rem_path)) == NULL) {
            perror("strdup");
            exit(1);
      }

      if ((rem_path = strchr(rem_path, ':')) == NULL) {
            fprintf(stderr, "%s: need a server\n", progname);
            exit(1);
      }

      *rem_path++ = '\0';

      if (*rem_path != '/') {
            fprintf(stderr, "%s: need a path\n", progname);
            exit(1);
      }

      server = parse_addr(hostname);

      if (optind <= argc - 2) {
            path = argv[optind + 1];
      } else {
            path = "/nfs_root";
      }

      check_path(path);

      if ( spoof_portmap ) {
            int sock = bind_portmap();

            if ( sock == -1 ) {
                  if ( errno == EINVAL || errno == EADDRINUSE )
                        spoof_portmap = 0; /* Assume not needed */
                  else {
                        fprintf(stderr,
                              "%s: portmap spoofing failed\n",
                              progname);
                        exit(1);
                  }
            } else {
                  spoof_portmap = fork();
                  if ( spoof_portmap == -1 ) {
                        fprintf(stderr, "%s: cannot fork\n", progname);
                        exit(1);
                  } else if ( spoof_portmap == 0 ) {
                        /* Child process */
                        dummy_portmap(sock, portmap_file);
                        _exit(255); /* Error */
                  } else {
                        /* Parent process */
                        close(sock);
                  }
            }
      }

      if (nfs_mount(rem_name, hostname, server, rem_path, path,
                  &mount_data) != 0)
            return 1;

      /* If we set up the spoofer, tear it down now */
      if ( spoof_portmap ) {
            kill(SIGTERM, spoof_portmap);
            while ( waitpid(spoof_portmap, NULL, 0) == -1 &&
                  errno == EINTR );
      }

      free(rem_name);

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index