[修改] 可编译,但为x86版本

This commit is contained in:
gaoyang3513
2023-10-18 16:38:31 +00:00
parent 71fbd7b818
commit 6ba4175d2b
6 changed files with 1768 additions and 8 deletions

View File

@ -31,12 +31,12 @@ MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
#*******************************************************************************
# Compile configure
#*******************************************************************************
export ARCH ?= arm
export CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
export ARCH ?= aarch64
export CROSS_COMPILE ?= /home/gaoyang3513/Workspaces/ndk/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-
export CC := /home/gaoyang3513/Workspaces/ndk/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
export LD := $(CROSS_COMPILE)ld
export AR := $(CROSS_COMPILE)ar
export STRIP := $(CROSS_COMPILE)strip
#*******************************************************************************
# Targets
@ -72,7 +72,10 @@ nfs-utils: checkenv
fi
if [ ! -e $(NFS_DIR)/Makefile ]; then \
cd $(NFS_DIR); \
./configure --prefix=$(INSTALL_DIR) --disable-nfsv4 --disable-gss --disable-uuid --disable-mount --sbindir=$(INSTALL_DIR)/sbin/ --with-statedir=$(INSTALL_DIR)/var/lig/nfs/; \
./configure --prefix=$(INSTALL_DIR) \
--target=aarch64-linux-android --host=aarch64-linux-android --build=x86_64-linux \
--disable-nfsv4 --disable-gss --disable-uuid --disable-mount \
--sbindir=$(INSTALL_DIR)/sbin/ --with-statedir=$(INSTALL_DIR)/var/lig/nfs/; \
fi
$(MAKE) -C $(NFS_DIR) all install

View File

@ -0,0 +1,256 @@
/*
* support/export/xtab.c
*
* Interface to the etab/exports file.
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include "nfslib.h"
#include "exportfs.h"
#include "xio.h"
#include "xlog.h"
#include "v4root.h"
#include "misc.h"
static char state_base_dirname[PATH_MAX] = NFS_STATEDIR;
extern struct state_paths etab;
int v4root_needed;
static void cond_rename(char *newfile, char *oldfile);
static int
xtab_read(char *xtab, char *lockfn, int is_export)
{
/* is_export == 0 => reading /proc/fs/nfs/exports - we know these things are exported to kernel
* is_export == 1 => reading /var/lib/nfs/etab - these things are allowed to be exported
*/
struct exportent *xp;
nfs_export *exp;
int lockid;
if ((lockid = xflock(lockfn, "r")) < 0)
return 0;
setexportent(xtab, "r");
if (is_export == 1)
v4root_needed = 1;
while ((xp = getexportent(is_export==0, 0)) != NULL) {
if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
!(exp = export_create(xp, is_export!=1))) {
if(xp->e_hostname) {
free(xp->e_hostname);
xp->e_hostname=NULL;
}
if(xp->e_uuid) {
free(xp->e_uuid);
xp->e_uuid=NULL;
}
continue;
}
switch (is_export) {
case 0:
exp->m_exported = 1;
break;
case 1:
exp->m_xtabent = 1;
exp->m_mayexport = 1;
if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
v4root_needed = 0;
break;
}
if(xp->e_hostname) {
free(xp->e_hostname);
xp->e_hostname=NULL;
}
if(xp->e_uuid) {
free(xp->e_uuid);
xp->e_uuid=NULL;
}
}
endexportent();
xfunlock(lockid);
return 0;
}
int
xtab_export_read(void)
{
return xtab_read(etab.statefn, etab.lockfn, 1);
}
/*
* mountd now keeps an open fd for the etab at all times to make sure that the
* inode number changes when the xtab_export_write is done. If you change the
* routine below such that the files are edited in place, then you'll need to
* fix the auth_reload logic as well...
*/
static int
xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
{
struct exportent xe;
nfs_export *exp;
int lockid, i;
if ((lockid = xflock(lockfn, "w")) < 0) {
xlog(L_ERROR, "can't lock %s for writing", xtab);
return 0;
}
setexportent(xtabtmp, "w");
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
if (is_export && !exp->m_xtabent)
continue;
if (!is_export && ! exp->m_exported)
continue;
/* write out the export entry using the FQDN */
xe = exp->m_export;
xe.e_hostname = exp->m_client->m_hostname;
putexportent(&xe);
}
}
endexportent();
cond_rename(xtabtmp, xtab);
xfunlock(lockid);
return 1;
}
int
xtab_export_write(void)
{
return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1);
}
/*
* rename newfile onto oldfile unless
* they are identical
*/
static void cond_rename(char *newfile, char *oldfile)
{
int nfd, ofd;
char nbuf[4096], obuf[4096];
int ncnt, ocnt;
nfd = open(newfile, 0);
if (nfd < 0)
return;
ofd = open(oldfile, 0);
if (ofd < 0) {
close(nfd);
rename(newfile, oldfile);
return;
}
do {
ncnt = read(nfd, nbuf, sizeof(nbuf));
if (ncnt < 0)
break;
ocnt = read(ofd, obuf, sizeof(obuf));
if (ocnt < 0)
break;
if (ncnt != ocnt)
break;
if (ncnt == 0) {
close(nfd);
close(ofd);
unlink(newfile);
return;
}
} while (memcmp(obuf, nbuf, ncnt) == 0);
/* some mis-match */
close(nfd);
close(ofd);
rename(newfile, oldfile);
return;
}
/*
* Returns a dynamically allocated, '\0'-terminated buffer
* containing an appropriate pathname, or NULL if an error
* occurs. Caller must free the returned result with free(3).
*/
static char *
state_make_pathname(const char *tabname)
{
return generic_make_pathname(state_base_dirname, tabname);
}
/**
* state_setup_basedir - set up basedir
* @progname: C string containing name of program, for error messages
* @parentdir: C string containing pathname to on-disk state, or NULL
*
* This runs before logging is set up, so error messages are directed
* to stderr.
*
* Returns true and sets up our basedir, if @parentdir was valid
* and usable; otherwise false is returned.
*/
_Bool
state_setup_basedir(const char *progname, const char *parentdir)
{
return generic_setup_basedir(progname, parentdir, state_base_dirname,
PATH_MAX);
}
int
setup_state_path_names(const char *progname, const char *statefn,
const char *tmpfn, const char *lockfn,
struct state_paths *paths)
{
paths->statefn = state_make_pathname(statefn);
if (!paths->statefn) {
fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
progname, statefn);
goto out_err;
}
paths->tmpfn = state_make_pathname(tmpfn);
if (!paths->tmpfn) {
fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
progname, tmpfn);
goto out_free_statefn;
}
paths->lockfn = state_make_pathname(lockfn);
if (!paths->lockfn) {
fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
progname, lockfn);
goto out_free_tmpfn;
}
return 1;
out_free_tmpfn:
free(paths->tmpfn);
out_free_statefn:
free(paths->statefn);
out_err:
return 0;
}
void
free_state_path_names(struct state_paths *paths)
{
free(paths->statefn);
free(paths->tmpfn);
free(paths->lockfn);
}

View File

@ -0,0 +1,191 @@
/*
* xcommon.c - various functions put together to avoid basic error checking.
*
* added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927
*
* 1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL>
* - added Native Language Support
*
* 2006-06-06 Amit Gud <agud@redhat.com>
* - Moved code snippets here from mount/sundries.c of util-linux
* and merged code from support/nfs/xmalloc.c by Olaf Kirch <okir@monad.swb.de> here.
*/
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xcommon.h"
#include "nls.h" /* _() */
void (*at_die)(void ) = NULL;
char *
xstrndup (const char *s, int n) {
char *t;
if (s == NULL)
die (EX_SOFTWARE, _("bug in xstrndup call"));
t = xmalloc(n+1);
strncpy(t,s,n);
t[n] = 0;
return t;
}
char *
xstrconcat2 (const char *s, const char *t) {
char *res;
if (!s) s = "";
if (!t) t = "";
res = xmalloc(strlen(s) + strlen(t) + 1);
strcpy(res, s);
strcat(res, t);
return res;
}
/* frees its first arg - typical use: s = xstrconcat3(s,t,u); */
char *
xstrconcat3 (const char *s, const char *t, const char *u) {
char *res;
int dofree = 1;
if (!s) s = "", dofree=0;
if (!t) t = "";
if (!u) u = "";
res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1);
strcpy(res, s);
strcat(res, t);
strcat(res, u);
if (dofree)
free((void *) s);
return res;
}
/* frees its first arg - typical use: s = xstrconcat4(s,t,u,v); */
char *
xstrconcat4 (const char *s, const char *t, const char *u, const char *v) {
char *res;
int dofree = 1;
if (!s) s = "", dofree=0;
if (!t) t = "";
if (!u) u = "";
if (!v) v = "";
res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1);
strcpy(res, s);
strcat(res, t);
strcat(res, u);
strcat(res, v);
if (dofree)
free((void *) s);
return res;
}
/* Non-fatal error. Print message and return. */
/* (print the message in a single printf, in an attempt
to avoid mixing output of several threads) */
void
nfs_error (const char *fmt, ...) {
va_list args;
char *fmt2;
fmt2 = xstrconcat2 (fmt, "\n");
va_start (args, fmt);
// vfprintf (stderr, fmt2, args);
va_end (args);
free (fmt2);
}
/* Make a canonical pathname from PATH. Returns a freshly malloced string.
It is up the *caller* to ensure that the PATH is sensible. i.e.
canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
is not a legal pathname for ``/dev/fd0''. Anything we cannot parse
we return unmodified. */
char *canonicalize (const char *path) {
char canonical[PATH_MAX+2];
if (path == NULL)
return NULL;
#if 1
if (streq(path, "none") ||
streq(path, "proc") ||
streq(path, "devpts"))
return xstrdup(path);
#endif
if (realpath (path, canonical))
return xstrdup(canonical);
return xstrdup(path);
}
/* Fatal error. Print message and exit. */
void
die(int err, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
if (at_die)
(*at_die)();
exit(err);
}
static void
die_if_null(void *t) {
if (t == NULL)
die(EX_SYSERR, _("not enough memory"));
}
void *
xmalloc (size_t size) {
void *t;
if (size == 0)
return NULL;
t = malloc(size);
die_if_null(t);
return t;
}
void *
xrealloc (void *p, size_t size) {
void *t;
t = realloc(p, size);
die_if_null(t);
return t;
}
void
xfree(void *ptr)
{
free(ptr);
}
char *
xstrdup (const char *s) {
char *t;
if (s == NULL)
return NULL;
t = strdup(s);
die_if_null(t);
return t;
}

View File

@ -0,0 +1,780 @@
/*
* utils/exportfs/exportfs.c
*
* Export file systems to knfsd
*
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*
* Extensive changes, 1999, Neil Brown <neilb@cse.unsw.edu.au>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <getopt.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#define INT_TO_LONG_THRESHOLD_SECS (INT_MAX - (60 * 60 * 24))
#include "sockaddr.h"
#include "misc.h"
#include "nfsd_path.h"
#include "nfslib.h"
#include "exportfs.h"
#include "xlog.h"
#include "conffile.h"
static void export_all(int verbose);
static void exportfs(char *arg, char *options, int verbose);
static void unexportfs(char *arg, int verbose);
static void dump(int verbose, int export_format);
static void usage(const char *progname, int n);
static void validate_export(nfs_export *exp);
static int matchhostname(const char *hostname1, const char *hostname2);
static void grab_lockfile(void);
static void release_lockfile(void);
static const char *lockfile = EXP_LOCKFILE;
static int _lockfd = -1;
struct state_paths etab;
static ssize_t exportfs_write(int fd, const char *buf, size_t len)
{
return nfsd_path_write(fd, buf, len);
}
/*
* If we aren't careful, changes made by exportfs can be lost
* when multiple exports process run at once:
*
* exportfs process 1 exportfs process 2
* ------------------------------------------
* reads etab version A reads etab version A
* adds new export B adds new export C
* writes A+B writes A+C
*
* The locking in support/export/xtab.c will prevent mountd from
* seeing a partially written version of etab, and will prevent
* the two writers above from writing simultaneously and
* corrupting etab, but to prevent problems like the above we
* need these additional lockfile() routines.
*/
static void
grab_lockfile(void)
{
_lockfd = open(lockfile, O_CREAT|O_RDWR, 0666);
if (_lockfd != -1)
lockf(_lockfd, F_LOCK, 0);
}
static void
release_lockfile(void)
{
if (_lockfd != -1) {
lockf(_lockfd, F_ULOCK, 0);
close(_lockfd);
_lockfd = -1;
}
}
int
main(int argc, char **argv)
{
char *options = NULL;
char *progname = NULL;
int f_export = 1;
int f_all = 0;
int f_verbose = 0;
int f_export_format = 0;
int f_reexport = 0;
int f_ignore = 0;
int i, c;
int force_flush = 0;
char *s;
if ((progname = strrchr(argv[0], '/')) != NULL)
progname++;
else
progname = argv[0];
xlog_open(progname);
xlog_stderr(1);
xlog_syslog(0);
conf_init_file(NFS_CONFFILE);
xlog_from_conffile("exportfs");
nfsd_path_init();
/* NOTE: following uses "mountd" section of nfs.conf !!!! */
s = conf_get_str("mountd", "state-directory-path");
if (s && !state_setup_basedir(argv[0], s))
exit(1);
while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) {
switch(c) {
case 'a':
f_all = 1;
break;
case 'd':
xlog_sconfig(optarg, 1);
break;
case 'f':
force_flush = 1;
break;
case 'h':
usage(progname, 0);
break;
case 'i':
f_ignore = 1;
break;
case 'o':
options = optarg;
break;
case 'r':
f_reexport = 1;
f_all = 1;
break;
case 'u':
f_export = 0;
break;
case 'v':
f_verbose = 1;
break;
case 's':
f_export_format = 1;
break;
default:
usage(progname, 1);
break;
}
}
if (optind != argc && f_all) {
xlog(L_ERROR, "extra arguments are not permitted with -a or -r");
return 1;
}
if (f_ignore && (f_all || ! f_export)) {
xlog(L_ERROR, "-i not meaningful with -a, -r or -u");
return 1;
}
if (f_reexport && ! f_export) {
xlog(L_ERROR, "-r and -u are incompatible");
return 1;
}
printf("point 1\n");
if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
return 1;
printf("point 2\n");
if (optind == argc && ! f_all) {
if (force_flush) {
cache_flush(1);
free_state_path_names(&etab);
return 0;
} else {
xtab_export_read();
dump(f_verbose, f_export_format);
free_state_path_names(&etab);
export_freeall();
return 0;
}
}
printf("point 3\n");
/*
* Serialize things as best we can
*/
grab_lockfile();
atexit(release_lockfile);
if (f_export && ! f_ignore) {
if (! (export_read(_PATH_EXPORTS, 0) +
export_d_read(_PATH_EXPORTS_D, 0))) {
if (f_verbose)
xlog(L_WARNING, "No file systems exported!");
}
}
if (f_export) {
if (f_all)
export_all(f_verbose);
else
for (i = optind; i < argc ; i++)
exportfs(argv[i], options, f_verbose);
}
/* If we are unexporting everything, then
* don't care about what should be exported, as that
* may require DNS lookups..
*/
if (! ( !f_export && f_all)) {
/* note: xtab_*_read does not update entries if they already exist,
* so this will not lose new options
*/
if (!f_reexport)
xtab_export_read();
if (!f_export)
for (i = optind ; i < argc ; i++)
unexportfs(argv[i], f_verbose);
}
xtab_export_write();
cache_flush(force_flush);
free_state_path_names(&etab);
export_freeall();
return export_errno;
}
/*
* export_all finds all entries and
* marks them xtabent and mayexport so that they get exported
*/
static void
export_all(int verbose)
{
nfs_export *exp;
int i;
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
if (verbose)
printf("exporting %s:%s\n",
exp->m_client->m_hostname,
exp->m_export.e_path);
exp->m_xtabent = 1;
exp->m_mayexport = 1;
exp->m_changed = 1;
exp->m_warned = 0;
validate_export(exp);
}
}
}
static void
exportfs_parsed(char *hname, char *path, char *options, int verbose)
{
struct exportent *eep;
nfs_export *exp = NULL;
struct addrinfo *ai = NULL;
int htype;
if ((htype = client_gettype(hname)) == MCL_FQDN) {
ai = host_addrinfo(hname);
if (ai != NULL) {
exp = export_find(ai, path);
hname = ai->ai_canonname;
}
} else
exp = export_lookup(hname, path, 0);
if (!exp) {
if (!(eep = mkexportent(hname, path, options)) ||
!(exp = export_create(eep, 0)))
goto out;
} else if (!updateexportent(&exp->m_export, options))
goto out;
if (verbose)
printf("exporting %s:%s\n", exp->m_client->m_hostname,
exp->m_export.e_path);
exp->m_xtabent = 1;
exp->m_mayexport = 1;
exp->m_changed = 1;
exp->m_warned = 0;
validate_export(exp);
out:
nfs_freeaddrinfo(ai);
}
static int exportfs_generic(char *arg, char *options, int verbose)
{
char *path;
if ((path = strchr(arg, ':')) != NULL)
*path++ = '\0';
if (!path || *path != '/')
return 1;
exportfs_parsed(arg, path, options, verbose);
return 0;
}
static int exportfs_ipv6(char *arg, char *options, int verbose)
{
char *path, *c;
arg++;
c = strchr(arg, ']');
if (c == NULL)
return 1;
/* no colon means this is a wildcarded DNS hostname */
if (memchr(arg, ':', c - arg) == NULL)
return exportfs_generic(--arg, options, verbose);
path = strstr(c, ":/");
if (path == NULL)
return 1;
*path++ = '\0';
/* if there's anything between the closing brace and the
* path separator, it's probably a prefix length */
memmove(c, c + 1, path - c);
exportfs_parsed(arg, path, options, verbose);
return 0;
}
static void
exportfs(char *arg, char *options, int verbose)
{
int failed;
if (*arg == '[')
failed = exportfs_ipv6(arg, options, verbose);
else
failed = exportfs_generic(arg, options, verbose);
if (failed)
xlog(L_ERROR, "Invalid export syntax: %s", arg);
}
static void
unexportfs_parsed(char *hname, char *path, int verbose)
{
nfs_export *exp;
struct addrinfo *ai = NULL;
int htype;
int success = 0;
if ((htype = client_gettype(hname)) == MCL_FQDN) {
ai = host_addrinfo(hname);
if (ai)
hname = ai->ai_canonname;
}
/*
* It's possible the specified path ends with a '/'. But
* the entry from exportlist won't has the trailing '/',
* so need to deal with it.
*/
size_t nlen = strlen(path);
while (path[nlen - 1] == '/')
nlen--;
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
if (strlen(exp->m_export.e_path) != nlen)
continue;
if (path && strncmp(path, exp->m_export.e_path, nlen))
continue;
if (htype != exp->m_client->m_type)
continue;
if (htype == MCL_FQDN
&& !matchhostname(exp->m_export.e_hostname,
hname))
continue;
if (htype != MCL_FQDN
&& strcasecmp(exp->m_export.e_hostname, hname))
continue;
if (verbose) {
#if 0
if (exp->m_exported) {
printf("unexporting %s:%s from kernel\n",
exp->m_client->m_hostname,
exp->m_export.e_path);
}
else
#endif
printf("unexporting %s:%s\n",
exp->m_client->m_hostname,
exp->m_export.e_path);
}
exp->m_xtabent = 0;
exp->m_mayexport = 0;
success = 1;
}
if (!success)
xlog(L_ERROR, "Could not find '%s:%s' to unexport.", hname, path);
nfs_freeaddrinfo(ai);
}
static int unexportfs_generic(char *arg, int verbose)
{
char *path;
if ((path = strchr(arg, ':')) != NULL)
*path++ = '\0';
if (!path || *path != '/')
return 1;
unexportfs_parsed(arg, path, verbose);
return 0;
}
static int unexportfs_ipv6(char *arg, int verbose)
{
char *path, *c;
arg++;
c = strchr(arg, ']');
if (c == NULL)
return 1;
/* no colon means this is a wildcarded DNS hostname */
if (memchr(arg, ':', c - arg) == NULL)
return unexportfs_generic(--arg, verbose);
path = strstr(c, ":/");
if (path == NULL)
return 1;
*path++ = '\0';
/* if there's anything between the closing brace and the
* path separator, it's probably a prefix length */
memmove(c, c + 1, path - c);
unexportfs_parsed(arg, path, verbose);
return 0;
}
static void
unexportfs(char *arg, int verbose)
{
int failed;
if (*arg == '[')
failed = unexportfs_ipv6(arg, verbose);
else
failed = unexportfs_generic(arg, verbose);
if (failed)
xlog(L_ERROR, "Invalid export syntax: %s", arg);
}
static int can_test(void)
{
char buf[1024] = { 0 };
int fd;
int n;
size_t bufsiz = sizeof(buf);
fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY);
if (fd < 0)
return 0;
/*
* We introduce tolerance of 1 day to ensure that we use a
* LONG_MAX for the expiry timestamp before it is actually
* needed. To use LONG_MAX, the kernel code must have
* commit 2f74f972 (sunrpc: prepare NFS for 2038).
*/
if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS)
snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX);
else
snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX);
n = write(fd, buf, strlen(buf));
close(fd);
if (n < 0)
return 0;
fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
if (fd < 0)
return 0;
close(fd);
return 1;
}
static int test_export(nfs_export *exp, int with_fsid)
{
char *path = exp->m_export.e_path;
int flags = exp->m_export.e_flags | (with_fsid ? NFSEXP_FSID : 0);
/* beside max path, buf size should take protocol str into account */
char buf[NFS_MAXPATHLEN+1+64] = { 0 };
char *bp = buf;
int len = sizeof(buf);
int fd, n;
n = snprintf(buf, len, "-test-client- ");
bp += n;
len -= n;
qword_add(&bp, &len, path);
if (len < 1)
return 0;
snprintf(bp, len, " 3 %d 65534 65534 0\n", flags);
fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
if (fd < 0)
return 0;
n = exportfs_write(fd, buf, strlen(buf));
close(fd);
if (n < 0)
return 0;
return 1;
}
static void
validate_export(nfs_export *exp)
{
/* Check that the given export point is potentially exportable.
* We just give warnings here, don't cause anything to fail.
* If a path doesn't exist, or is not a dir or file, give an warning
* otherwise trial-export to '-test-client-' and check for failure.
*/
struct stat stb;
char *path = exportent_realpath(&exp->m_export);
struct statfs64 stf;
int fs_has_fsid = 0;
if (stat(path, &stb) < 0) {
xlog(L_ERROR, "Failed to stat %s: %m", path);
return;
}
if (!S_ISDIR(stb.st_mode)) {
xlog(L_ERROR, "%s is not a directory. "
"Remote access will fail", path);
return;
}
if (!can_test())
return;
if (!statfs64(path, &stf) &&
(stf.f_fsid.__val[0] || stf.f_fsid.__val[1]))
fs_has_fsid = 1;
if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
fs_has_fsid) {
if ( !test_export(exp, 1)) {
xlog(L_ERROR, "%s does not support NFS export", path);
return;
}
} else if ( !test_export(exp, 0)) {
if (test_export(exp, 1))
xlog(L_ERROR, "%s requires fsid= for NFS export", path);
else
xlog(L_ERROR, "%s does not support NFS export", path);
return;
}
}
static _Bool
is_hostname(const char *sp)
{
if (*sp == '\0' || *sp == '@')
return false;
for (; *sp != '\0'; sp++) {
if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
return false;
if (*sp == '\\' && sp[1] != '\0')
sp++;
}
return true;
}
/*
* Take care to perform an explicit reverse lookup on presentation
* addresses. Otherwise we don't get a real canonical name or a
* complete list of addresses.
*/
static struct addrinfo *
address_list(const char *hostname)
{
struct addrinfo *ai;
char *cname;
ai = host_pton(hostname);
if (ai != NULL) {
/* @hostname was a presentation address */
cname = host_canonname(ai->ai_addr);
nfs_freeaddrinfo(ai);
if (cname != NULL)
goto out;
}
/* @hostname was a hostname or had no reverse mapping */
cname = strdup(hostname);
if (cname == NULL)
return NULL;
out:
ai = host_addrinfo(cname);
free(cname);
return ai;
}
static int
matchhostname(const char *hostname1, const char *hostname2)
{
struct addrinfo *results1 = NULL, *results2 = NULL;
struct addrinfo *ai1, *ai2;
int result = 0;
if (strcasecmp(hostname1, hostname2) == 0)
return 1;
/*
* Don't pass export wildcards or netgroup names to DNS
*/
if (!is_hostname(hostname1) || !is_hostname(hostname2))
return 0;
results1 = address_list(hostname1);
if (results1 == NULL)
goto out;
results2 = address_list(hostname2);
if (results2 == NULL)
goto out;
if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
result = 1;
goto out;
}
for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
result = 1;
break;
}
out:
nfs_freeaddrinfo(results1);
nfs_freeaddrinfo(results2);
return result;
}
#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
__attribute__((format (printf, 2, 3)))
#endif
static char
dumpopt(char c, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
printf("%c", c);
vprintf(fmt, ap);
va_end(ap);
return ',';
}
static void
dump(int verbose, int export_format)
{
/* buf[] size should >= sizeof(struct exportent->e_path) */
char buf[NFS_MAXPATHLEN+1] = { 0 };
char *bp;
int len;
nfs_export *exp;
struct exportent *ep;
int htype;
char *hname, c;
for (htype = 0; htype < MCL_MAXTYPES; htype++) {
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
ep = &exp->m_export;
if (!exp->m_xtabent)
continue; /* neilb */
if (htype == MCL_ANONYMOUS)
hname = (export_format) ? "*" : "<world>";
else
hname = ep->e_hostname;
if (strlen(ep->e_path) > 14 && !export_format)
printf("%-14s\n\t\t%s", ep->e_path, hname);
else
if (export_format) {
bp = buf;
len = sizeof(buf) - 1;
qword_add(&bp, &len, ep->e_path);
*bp = '\0';
printf("%s %s", buf, hname);
} else {
printf("%-14s\t%s", ep->e_path, hname);
}
if (!verbose && !export_format) {
printf("\n");
continue;
}
c = '(';
if (ep->e_flags & NFSEXP_ASYNC)
c = dumpopt(c, "async");
else
c = dumpopt(c, "sync");
if (ep->e_flags & NFSEXP_GATHERED_WRITES)
c = dumpopt(c, "wdelay");
else
c = dumpopt(c, "no_wdelay");
if (ep->e_flags & NFSEXP_NOHIDE)
c = dumpopt(c, "nohide");
else
c = dumpopt(c, "hide");
if (ep->e_flags & NFSEXP_CROSSMOUNT)
c = dumpopt(c, "crossmnt");
if (ep->e_flags & NFSEXP_NOSUBTREECHECK)
c = dumpopt(c, "no_subtree_check");
if (ep->e_flags & NFSEXP_NOAUTHNLM)
c = dumpopt(c, "insecure_locks");
if (ep->e_flags & NFSEXP_NOREADDIRPLUS)
c = dumpopt(c, "nordirplus");
if (ep->e_flags & NFSEXP_SECURITY_LABEL)
c = dumpopt(c, "security_label");
if (ep->e_flags & NFSEXP_NOACL)
c = dumpopt(c, "no_acl");
if (ep->e_flags & NFSEXP_PNFS)
c = dumpopt(c, "pnfs");
if (ep->e_flags & NFSEXP_FSID)
c = dumpopt(c, "fsid=%d", ep->e_fsid);
if (ep->e_uuid)
c = dumpopt(c, "fsid=%s", ep->e_uuid);
if (ep->e_mountpoint)
c = dumpopt(c, "mountpoint%s%s",
ep->e_mountpoint[0]?"=":"",
ep->e_mountpoint);
if (ep->e_anonuid != 65534)
c = dumpopt(c, "anonuid=%d", ep->e_anonuid);
if (ep->e_anongid != 65534)
c = dumpopt(c, "anongid=%d", ep->e_anongid);
switch(ep->e_fslocmethod) {
case FSLOC_NONE:
break;
case FSLOC_REFER:
c = dumpopt(c, "refer=%s", ep->e_fslocdata);
break;
case FSLOC_REPLICA:
c = dumpopt(c, "replicas=%s", ep->e_fslocdata);
break;
#ifdef DEBUG
case FSLOC_STUB:
c = dumpopt(c, "fsloc=stub");
break;
#endif
}
secinfo_show(stdout, ep);
printf("%c\n", (c != '(')? ')' : ' ');
}
}
}
static void
usage(const char *progname, int n)
{
fprintf(stderr, "usage: %s [-adfhioruvs] [host:/path]\n", progname);
exit(n);
}

View File

@ -0,0 +1,316 @@
/*
* utils/mountd/auth.c
*
* Authentication procedures for mountd.
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "sockaddr.h"
#include "misc.h"
#include "nfslib.h"
#include "exportfs.h"
#include "mountd.h"
#include "v4root.h"
enum auth_error
{
bad_path,
unknown_host,
no_entry,
not_exported,
illegal_port,
success
};
static void auth_fixpath(char *path);
static nfs_export my_exp;
static nfs_client my_client;
extern int use_ipaddr;
extern struct state_paths etab;
void
auth_init(void)
{
auth_reload();
}
/*
* 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(void)
{
struct stat stb;
static ino_t last_inode;
static int last_fd = -1;
static unsigned int counter;
int fd;
if ((fd = open(etab.statefn, O_RDONLY)) < 0) {
xlog(L_FATAL, "couldn't open %s", etab.statefn);
} else if (fstat(fd, &stb) < 0) {
xlog(L_FATAL, "couldn't stat %s", etab.statefn);
close(fd);
} else if (last_fd != -1 && stb.st_ino == last_inode) {
/* We opened the etab file before, and its inode
* number hasn't changed since then.
*/
close(fd);
return counter;
} else {
/* Need to process entries from the etab file. Close
* the file descriptor from the previous open (last_fd),
* and keep the current file descriptor open to prevent
* the file system reusing the current inode number
* (last_inode).
*/
if (last_fd != -1)
close(last_fd);
last_fd = fd;
last_inode = stb.st_ino;
}
export_freeall();
memset(&my_client, 0, sizeof(my_client));
xtab_export_read();
check_useipaddr();
v4root_set();
++counter;
return counter;
}
static char *get_client_ipaddr_name(const struct sockaddr *caller)
{
char buf[INET6_ADDRSTRLEN + 1];
buf[0] = '$';
host_ntop(caller, buf + 1, sizeof(buf) - 1);
return strdup(buf);
}
static char *
get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
enum auth_error *error)
{
char *n;
if (use_ipaddr)
return get_client_ipaddr_name(caller);
n = client_compose(ai);
*error = unknown_host;
if (!n)
return NULL;
if (*n)
return n;
free(n);
return strdup("DEFAULT");
}
bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai)
{
return client_check(exp->m_client, ai);
}
bool namelist_client_matches(nfs_export *exp, char *dom)
{
return client_member(dom, exp->m_client->m_hostname);
}
bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
{
if (is_ipaddr_client(dom))
return ipaddr_client_matches(exp, ai);
return namelist_client_matches(exp, dom);
}
/* return static nfs_export with details filled in */
static nfs_export *
auth_authenticate_newcache(const struct sockaddr *caller,
const char *path, struct addrinfo *ai,
enum auth_error *error)
{
nfs_export *exp;
int i;
free(my_client.m_hostname);
my_client.m_hostname = get_client_hostname(caller, ai, error);
if (my_client.m_hostname == NULL)
return NULL;
my_client.m_naddr = 1;
set_addrlist(&my_client, 0, caller);
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 (!client_matches(exp, my_client.m_hostname, ai))
continue;
if (exp->m_export.e_flags & NFSEXP_V4ROOT)
/* not acceptable for v[23] export */
continue;
break;
}
*error = not_exported;
if (!exp)
return NULL;
my_exp.m_export = exp->m_export;
exp = &my_exp;
return exp;
}
static nfs_export *
auth_authenticate_internal(const struct sockaddr *caller, const char *path,
struct addrinfo *ai, enum auth_error *error)
{
nfs_export *exp;
exp = auth_authenticate_newcache(caller, path, ai, error);
if (!exp)
return NULL;
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
nfs_get_port(caller) >= IPPORT_RESERVED) {
*error = illegal_port;
return NULL;
}
*error = success;
return exp;
}
nfs_export *
auth_authenticate(const char *what, const struct sockaddr *caller,
const char *path)
{
nfs_export *exp = NULL;
char epath[MAXPATHLEN+1];
char *p = NULL;
char buf[INET6_ADDRSTRLEN];
struct addrinfo *ai = NULL;
enum auth_error error = bad_path;
if (path[0] != '/') {
xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
what, host_ntop(caller, buf, sizeof(buf)), path);
return exp;
}
strncpy(epath, path, sizeof (epath) - 1);
epath[sizeof (epath) - 1] = '\0';
auth_fixpath(epath); /* strip duplicate '/' etc */
ai = client_resolve(caller);
if (ai == NULL)
return exp;
/* Try the longest matching exported pathname. */
while (1) {
exp = auth_authenticate_internal(caller, epath, ai, &error);
if (exp || (error != not_exported && error != no_entry))
break;
/* We have to treat the root, "/", specially. */
if (p == &epath[1]) break;
p = strrchr(epath, '/');
if (p == epath) p++;
*p = '\0';
}
host_ntop(caller, buf, sizeof(buf));
switch (error) {
case bad_path:
xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
what, buf, path);
break;
case unknown_host:
xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
what, buf, path, epath);
break;
case no_entry:
xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
what, buf, path, epath);
break;
case not_exported:
xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
what, buf, path, epath);
break;
case illegal_port:
xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
what, buf, path, epath, nfs_get_port(caller));
break;
case success:
xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
what, buf, nfs_get_port(caller), path, epath);
break;
default:
xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
what, buf, nfs_get_port(caller), path, epath, error);
}
nfs_freeaddrinfo(ai);
return exp;
}
static void
auth_fixpath(char *path)
{
char *sp, *cp;
for (sp = cp = path; *sp; sp++) {
if (*sp != '/' || sp[1] != '/')
*cp++ = *sp;
}
while (cp > path+1 && cp[-1] == '/')
cp--;
*cp = '\0';
}

View File

@ -0,0 +1,214 @@
/*
* Copyright (C) 2009 Red Hat <nfs@redhat.com>
*
* support/export/v4root.c
*
* Routines used to support NFSv4 pseudo roots
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include "xlog.h"
#include "exportfs.h"
#include "nfslib.h"
#include "misc.h"
#include "v4root.h"
#include "pseudoflavors.h"
static nfs_export pseudo_root = {
.m_next = NULL,
.m_client = NULL,
.m_export = {
.e_hostname = "*",
.e_path = "/",
.e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
| NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
| NFSEXP_V4ROOT,
.e_anonuid = 65534,
.e_anongid = 65534,
.e_squids = NULL,
.e_nsquids = 0,
.e_sqgids = NULL,
.e_nsqgids = 0,
.e_fsid = 0,
.e_mountpoint = NULL,
.e_ttl = DEFAULT_TTL,
},
.m_exported = 0,
.m_xtabent = 1,
.m_mayexport = 1,
.m_changed = 0,
.m_warned = 0,
};
static void
set_pseudofs_security(struct exportent *pseudo, int flags)
{
struct flav_info *flav;
int i;
if (flags & NFSEXP_INSECURE_PORT)
pseudo->e_flags |= NFSEXP_INSECURE_PORT;
if ((flags & NFSEXP_ROOTSQUASH) == 0)
pseudo->e_flags &= ~NFSEXP_ROOTSQUASH;
for (flav = flav_map; flav < flav_map + flav_map_size; flav++) {
struct sec_entry *new;
if (!flav->fnum)
continue;
i = secinfo_addflavor(flav, pseudo);
new = &pseudo->e_secinfo[i];
if (flags & NFSEXP_INSECURE_PORT)
new->flags |= NFSEXP_INSECURE_PORT;
}
}
/*
* Create a pseudo export
*/
static struct exportent *
v4root_create(char *path, nfs_export *export)
{
nfs_export *exp;
struct exportent eep;
struct exportent *curexp = &export->m_export;
dupexportent(&eep, &pseudo_root.m_export);
eep.e_hostname = curexp->e_hostname;
strncpy(eep.e_path, path, sizeof(eep.e_path)-1);
if (strcmp(path, "/") != 0)
eep.e_flags &= ~NFSEXP_FSID;
set_pseudofs_security(&eep, curexp->e_flags);
exp = export_create(&eep, 0);
if (exp == NULL)
return NULL;
xlog(D_CALL, "v4root_create: path '%s' flags 0x%x",
exp->m_export.e_path, exp->m_export.e_flags);
return &exp->m_export;
}
/*
* Make sure the kernel has pseudo root support.
*/
static int
v4root_support(void)
{
struct export_features *ef;
static int warned = 0;
ef = get_export_features();
if (ef->flags & NFSEXP_V4ROOT)
return 1;
if (!warned) {
xlog(L_WARNING, "Kernel does not have pseudo root support.");
xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
xlog(L_WARNING, "is specfied in /etc/exports file.");
warned++;
}
return 0;
}
static int
pseudofs_update(char *hostname, char *path, nfs_export *source)
{
nfs_export *exp;
exp = export_lookup(hostname, path, 0);
if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
return 0;
if (!exp) {
if (v4root_create(path, source) == NULL) {
xlog(L_WARNING, "v4root_set: Unable to create "
"pseudo export for '%s'", path);
return -ENOMEM;
}
return 0;
}
/* Update an existing V4ROOT export: */
set_pseudofs_security(&exp->m_export, source->m_export.e_flags);
return 0;
}
static int v4root_add_parents(nfs_export *exp)
{
char *hostname = exp->m_export.e_hostname;
char *path;
char *ptr;
int ret = 0;
path = strdup(exp->m_export.e_path);
if (!path) {
xlog(L_WARNING, "v4root_add_parents: Unable to create "
"pseudo export for '%s'", exp->m_export.e_path);
return -ENOMEM;
}
for (ptr = path; ptr; ptr = strchr(ptr, '/')) {
char saved;
saved = *ptr;
*ptr = '\0';
ret = pseudofs_update(hostname, *path ? path : "/", exp);
if (ret)
break;
*ptr = saved;
ptr++;
}
free(path);
return ret;
}
/*
* Create pseudo exports by running through the real export
* looking at the components of the path that make up the export.
* Those path components, if not exported, will become pseudo
* exports allowing them to be found when the kernel does an upcall
* looking for components of the v4 mount.
*/
void
v4root_set(void)
{
nfs_export *exp;
int i;
if (!v4root_needed)
return;
if (!v4root_support())
return;
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
if (exp->m_export.e_flags & NFSEXP_V4ROOT)
/*
* We just added this one, so its
* parents are already dealt with!
*/
continue;
if (strcmp(exp->m_export.e_path, "/") == 0 &&
!(exp->m_export.e_flags & NFSEXP_FSID)) {
/* Force '/' to be exported as fsid == 0*/
exp->m_export.e_flags |= NFSEXP_FSID;
exp->m_export.e_fsid = 0;
}
v4root_add_parents(exp);
/* XXX: error handling! */
}
}
}