diff options
author | hjl <hjl> | 1999-10-18 23:21:12 +0000 |
---|---|---|
committer | hjl <hjl> | 1999-10-18 23:21:12 +0000 |
commit | 8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9 (patch) | |
tree | 0904ef8554ed680fe3244fa618685e1fb7ea148b /support/nfs | |
download | nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.gz nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.xz nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.zip |
Initial revision
Diffstat (limited to 'support/nfs')
-rw-r--r-- | support/nfs/Makefile | 13 | ||||
-rw-r--r-- | support/nfs/clients.c | 324 | ||||
-rw-r--r-- | support/nfs/exports.c | 440 | ||||
-rw-r--r-- | support/nfs/getfh.c | 55 | ||||
-rw-r--r-- | support/nfs/keytab.c | 129 | ||||
-rw-r--r-- | support/nfs/lockdsvc.c | 20 | ||||
-rw-r--r-- | support/nfs/nfsclient.c | 32 | ||||
-rw-r--r-- | support/nfs/nfsctl.c | 24 | ||||
-rw-r--r-- | support/nfs/nfsexport.c | 32 | ||||
-rw-r--r-- | support/nfs/nfssvc.c | 22 | ||||
-rw-r--r-- | support/nfs/rmtab.c | 122 | ||||
-rw-r--r-- | support/nfs/rpcdispatch.c | 112 | ||||
-rw-r--r-- | support/nfs/rpcmisc.c | 230 | ||||
-rw-r--r-- | support/nfs/wildmat.c | 177 | ||||
-rw-r--r-- | support/nfs/xio.c | 151 | ||||
-rw-r--r-- | support/nfs/xlog.c | 189 | ||||
-rw-r--r-- | support/nfs/xmalloc.c | 48 | ||||
-rw-r--r-- | support/nfs/ypupdate_xdr.c | 29 |
18 files changed, 2149 insertions, 0 deletions
diff --git a/support/nfs/Makefile b/support/nfs/Makefile new file mode 100644 index 0000000..ed1e1ff --- /dev/null +++ b/support/nfs/Makefile @@ -0,0 +1,13 @@ +# +# linux-nfs/support/nfs/Makefile +# + +LIBNAME = libnfs.a +OBJS = exports.o rmtab.o xio.o \ + rpcmisc.o rpcdispatch.o xlog.o xmalloc.o wildmat.o \ + nfssvc.o nfsclient.o nfsexport.o getfh.o nfsctl.o lockdsvc.o + +include $(TOP)rules.mk + +install:: + @: diff --git a/support/nfs/clients.c b/support/nfs/clients.c new file mode 100644 index 0000000..b1970e0 --- /dev/null +++ b/support/nfs/clients.c @@ -0,0 +1,324 @@ +/* + * support/nfs/nfsclient.c + * + * Parse the nfsclients file. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> +#include "xmalloc.h" +#include "nfslib.h" +#include "exportfs.h" +#include "xio.h" + +static XFILE *cfp = NULL; +static int *squash_uids = NULL, + *squash_gids = NULL; +static int squash_uidlen = 0, + squash_gidlen = 0; +static char *hosts = NULL; + +static int parsesquash(char *list, int **idp, int *lenp); +static int parsenum(char **cpp); +static int parsekey(struct nfskey *keyp, char *str); +static int hexdigit(char c); +static int gettag(char *tag, int len); +static int getattr(char *attr, int alen, char *value, int vlen); +static void syntaxerr(char *msg); + +#ifndef isblank +#define isblank(c) ((c) == ' ' || (c) == '\t') +#endif + +void +setnfsclntent(char *fname) +{ + if (cfp) + xfclose(cfp); + if (!fname) + fname = _PATH_NFSCLIENTS; + if ((cfp = xfopen(fname)) == NULL) + xlog(L_ERROR, "can't open %s for reading", fname); +} + +struct nfsclntent * +getnfsclntent(void) +{ + static struct nfsclntent cle; + static char *hostptr = NULL; + char attr[32], val[512], *sp; + int ok; + + if (!cfp) + endnfsclntent(); + +again: + if (hosts) { + if (hostptr) + goto nexthost; + xfree(hosts); + hosts = NULL; + } + + if ((ok = gettag(cle.c_tag, sizeof(cle.c_tag))) < 0) + syntaxerr("expected tag"); + if (ok <= 0) + return NULL; + + cle.c_hostname[0] = '\0'; + cle.c_fhkey.k_type = CLE_KEY_NONE; + cle.c_mapping = CLE_MAP_IDENT; + cle.c_anonuid = -2; + cle.c_anongid = -2; + + if (squash_uids) + xfree(squash_uids); + if (squash_gids) + xfree(squash_gids); + squash_uids = squash_gids = NULL; + squash_uidlen = squash_gidlen = 0; + + while (ok) { + if ((ok = getattr(attr, sizeof(attr), val, sizeof(val))) < 0) + return NULL; + if (!ok) + break; + if (attr[0] == 'h' && !strcmp(attr, "hosts")) { + int l0 = hosts? strlen(hosts) : 0; + + hosts = (char *) xrealloc(hosts, l0+strlen(val)+2); + if (l0) + hosts[l0++] = ':'; + strcpy(hosts+l0, val); + } else + if (attr[0] == 'f' && !strcmp(attr, "fhmac")) { + if (!parsekey(&cle.c_fhkey, val)) + return NULL; + } else + if (attr[0] == 'm' && !strcmp(attr, "mapping")) { + if (!strcmp(val, "identity")) + cle.c_mapping = CLE_MAP_IDENT; + else if (!strcmp(val, "file")) + cle.c_mapping = CLE_MAP_FILE; + else if (!strcmp(val, "daemon")) + cle.c_mapping = CLE_MAP_UGIDD; + else { + syntaxerr("invalid mapping type"); + return NULL; + } + } else + if (attr[0] == 's' && !strcmp(attr, "squash_uids")) { + if (!parsesquash(val, &squash_uids, &squash_uidlen)) + return NULL; + } else + if (attr[0] == 's' && !strcmp(attr, "squash_gids")) { + if (!parsesquash(val, &squash_gids, &squash_gidlen)) + return NULL; + } else + if (attr[0] == 'a' && !strcmp(attr, "anonuid")) + cle.c_anonuid = atoi(val); + else + if (attr[0] == 'a' && !strcmp(attr, "anongid")) + cle.c_anongid = atoi(val); + else + syntaxerr("unknown attribute"); + } + + cle.c_squashuids = squash_uids; + cle.c_squashgids = squash_gids; + + /* This is the anon entry */ + if (!hosts) { + if (strcmp(cle.c_tag, "anonymous")) { + xlog(L_ERROR, "nfsclients entry %s allows anonymous " + "access. Ignored.", cle.c_tag); + goto again; + } + return &cle; + } + hostptr = hosts; + +nexthost: + if (*hostptr == ':' && strcmp(cle.c_tag, "anonymous")) { + xlog(L_ERROR, "nfsclients entry %s allows anonymous " + "access. Ignored.", cle.c_tag); + while (*hostptr == ':') + hostptr++; + } + + /* Ignore trailing colons */ + if (!*hostptr) { + hostptr = NULL; + goto again; + } + + sp = hostptr; + hostptr = strchr(hostptr, ':'); + if (hostptr) + *hostptr++ = '\0'; + strncpy(cle.c_hostname, sp, sizeof(cle.c_hostname) - 1); + cle.c_hostname [sizeof(cle.c_hostname) - 1] = '\0'; + return &cle; +} + +void +endnfsclntent(void) +{ + if (cfp) + xfclose(cfp); + if (squash_uids) + xfree(squash_uids); + if (squash_gids) + xfree(squash_gids); + if (hosts) + xfree(hosts); + cfp = NULL; + squash_uids = NULL; + squash_gids = NULL; + hosts = NULL; +} + +static int +parsekey(struct nfskey *keyp, char *str) +{ + char *sp; + int i, l, x0, x1; + + + if ((sp = strchr(str, ':')) != NULL) + *sp++ = '\0'; + if (!strcmp(str, "null")) + keyp->k_type = CLE_KEY_NULL; + else if (!strcmp(str, "md5")) + keyp->k_type = CLE_KEY_MD5; + else if (!strcmp(str, "sha")) + keyp->k_type = CLE_KEY_SHA; + else { + syntaxerr("unknown key type"); + return 0; + } + if (keyp->k_type == CLE_KEY_NULL) { + keyp->k_len = 0; + if (sp) + syntaxerr("unexpected key data for null key"); + return sp? 0 : 1; + } else if (sp) { + if ((l = strlen(sp)) & 1) { + syntaxerr("odd key length"); + return 0; + } + + l >>= 1; + for (i = 0; i < l && i < sizeof(keyp->k_key); i++, sp += 2) { + if ((x0 = hexdigit(sp[0])) == 0xff || + (x1 = hexdigit(sp[1])) == 0xff) { + syntaxerr("bad key digit"); + return 0; + } + keyp->k_key[i] = (x0 << 4) | x1; + } + keyp->k_len = i; + return 1; + } + return 0; +} + +static int +hexdigit(char c) +{ + if ((c = tolower(c)) >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0xff; +} + +static int +parsesquash(char *list, int **idp, int *lenp) +{ + char *cp = list; + int id0, id1; + int len = *lenp; + int *id = *idp; + + do { + id0 = parsenum(&cp); + if (*cp == '-') { + cp++; + id1 = parsenum(&cp); + } else { + id1 = id0; + } + if (id0 == -1 || id1 == -1) { + syntaxerr("uid/gid -1 not permitted"); + return 0; + } + if ((len % 8) == 0) + id = (int *) xrealloc(id, (len + 9) * sizeof(*id)); + id[len++] = id0; + id[len++] = id1; + if (!*cp) + break; + if (*cp != ',') { + syntaxerr("bad uid/gid list"); + return 0; + } + cp++; + } while(1); + + id[len] = -1; + *lenp = len; + *idp = id; + return 1; +} + +static int +parsenum(char **cpp) +{ + char *cp = *cpp, c; + int num = 0; + + if (**cpp == '-') + (*cpp)++; + while (isdigit(**cpp)) + (*cpp)++; + c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c; + return num; +} + +static int +gettag(char *tag, int len) +{ + xskip(cfp, " \t\n"); + return xgettok(cfp, ':', tag, len); +} + +static int +getattr(char *attr, int alen, char *value, int vlen) +{ + int ok; + + xskip(cfp, " \t"); + if ((ok = xgettok(cfp, '=', attr, alen)) < 0) + xlog(L_ERROR, "error parsing attribute"); + if (ok <= 0) + return ok; + xskip(cfp, " \t="); + + return xgettok(cfp, 0, value, vlen); +} + +static void +syntaxerr(char *msg) +{ + xlog(L_ERROR, "syntax error in nfsclients file (line %d): %s", + cfp->x_line, msg); +} + diff --git a/support/nfs/exports.c b/support/nfs/exports.c new file mode 100644 index 0000000..21b85be --- /dev/null +++ b/support/nfs/exports.c @@ -0,0 +1,440 @@ +/* + * support/nfs/export.c + * + * Parse the exports file. Derived from the unfsd implementation. + * + * Authors: Donald J. Becker, <becker@super.org> + * Rick Sladkey, <jrs@world.std.com> + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Olaf Kirch, <okir@monad.swb.de> + * Alexander O. Yuriev, <alex@bach.cis.temple.edu> + * + * This software maybe be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#include "config.h" + +#include <sys/param.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include "nfslib.h" +#include "exportfs.h" +#include "xmalloc.h" +#include "xlog.h" +#include "xio.h" + +#define EXPORT_DEFAULT_FLAGS \ + (NFSEXP_ASYNC|NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES) + +static XFILE *efp = NULL; +static int first; +static int *squids = NULL, nsquids = 0, + *sqgids = NULL, nsqgids = 0; + +static int getexport(char *exp, int len); +static int getpath(char *path, int len); +static int parseopts(char *cp, struct exportent *ep); +static int parsesquash(char *list, int **idp, int *lenp, char **ep); +static int parsenum(char **cpp); +static int parsemaptype(char *type); +static void freesquash(void); +static void syntaxerr(char *msg); + +void +setexportent(char *fname, char *type) +{ + if (efp) + endexportent(); + if (!fname) + fname = _PATH_EXPORTS; + if (!(efp = xfopen(fname, type))) + xlog(L_ERROR, "can't open %s for %sing", + fname, strcmp(type, "r")? "writ" : "read"); + first = 1; +} + +struct exportent * +getexportent(void) +{ + static struct exportent ee; + char exp[512]; + char rpath[MAXPATHLEN+1]; + char *opt, *sp; + int ok; + + if (!efp) + return NULL; + + freesquash(); + ee.e_flags = EXPORT_DEFAULT_FLAGS; + ee.e_maptype = CLE_MAP_IDENT; + ee.e_anonuid = -2; + ee.e_anongid = -2; + ee.e_squids = NULL; + ee.e_sqgids = NULL; + ee.e_nsquids = 0; + ee.e_nsqgids = 0; + + if (first || (ok = getexport(exp, sizeof(exp))) == 0) { + ok = getpath(ee.e_path, sizeof(ee.e_path)); + if (ok <= 0) + return NULL; + strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1); + ee.m_path [sizeof (ee.m_path) - 1] = '\0'; + ok = getexport(exp, sizeof(exp)); + } + if (ok < 0) { + xlog(L_ERROR, "expected client(options...)"); + return NULL; + } + first = 0; + + /* Check for default client */ + if (ok == 0) + exp[0] = '\0'; + if ((opt = strchr(exp, '(')) != NULL) { + *opt++ = '\0'; + if (!(sp = strchr(opt, ')')) || sp[1] != '\0') { + syntaxerr("bad option list"); + return NULL; + } + *sp = '\0'; + if (parseopts(opt, &ee) < 0) + return NULL; + } + if (strlen(exp) >= sizeof(ee.e_hostname)) { + syntaxerr("client name too long"); + return NULL; + } + strncpy(ee.e_hostname, exp, sizeof (ee.e_hostname) - 1); + ee.e_hostname[sizeof (ee.e_hostname) - 1] = '\0'; + + /* resolve symlinks */ + if (realpath(ee.e_path, rpath) != NULL) { + rpath[sizeof (rpath) - 1] = '\0'; + strncpy(ee.e_path, rpath, sizeof (ee.e_path) - 1); + ee.e_path[sizeof (ee.e_path) - 1] = '\0'; + strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1); + ee.m_path [sizeof (ee.m_path) - 1] = '\0'; + } + + return ⅇ +} + +void +putexportent(struct exportent *ep) +{ + FILE *fp; + int *id, i; + + if (!efp) + return; + + fp = efp->x_fp; + fprintf(fp, "%s\t%s(", ep->e_path, ep->e_hostname); + fprintf(fp, "%s,", (ep->e_flags & NFSEXP_READONLY)? "ro" : "rw"); + fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : ""); + fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)? + "" : "no_"); + fprintf(fp, "%ssecure,", (ep->e_flags & NFSEXP_INSECURE_PORT)? + "in" : ""); + fprintf(fp, "%sroot_squash,", (ep->e_flags & NFSEXP_ROOTSQUASH)? + "" : "no_"); + fprintf(fp, "%sall_squash,", (ep->e_flags & NFSEXP_ALLSQUASH)? + "" : "no_"); + + fprintf(fp, "mapping="); + switch (ep->e_maptype) { + case CLE_MAP_IDENT: + fprintf(fp, "identity,"); + break; + case CLE_MAP_UGIDD: + fprintf(fp, "ugidd,"); + break; + case CLE_MAP_FILE: + fprintf(fp, "file,"); + break; + default: + xlog(L_ERROR, "unknown mapping type for %s:%s", + ep->e_hostname, ep->e_path); + } + if ((id = ep->e_squids) != NULL) { + fprintf(fp, "squash_uids="); + for (i = 0; i < ep->e_nsquids; i += 2) + if (id[i] != id[i+1]) + fprintf(fp, "%d-%d,", id[i], id[i+1]); + else + fprintf(fp, "%d,", id[i]); + } + if ((id = ep->e_sqgids) != NULL) { + fprintf(fp, "squash_gids="); + for (i = 0; i < ep->e_nsquids; i += 2) + if (id[i] != id[i+1]) + fprintf(fp, "%d-%d,", id[i], id[i+1]); + else + fprintf(fp, "%d,", id[i]); + } + fprintf(fp, "anonuid=%d,anongid=%d)\n", ep->e_anonuid, ep->e_anongid); +} + +void +endexportent(void) +{ + if (efp) + xfclose(efp); + efp = NULL; + freesquash(); +} + +void +dupexportent(struct exportent *dst, struct exportent *src) +{ + int n; + + *dst = *src; + if ((n = src->e_nsquids) != 0) { + dst->e_squids = (int *) xmalloc(n * sizeof(int)); + memcpy(dst->e_squids, src->e_squids, n * sizeof(int)); + } + if ((n = src->e_nsqgids) != 0) { + dst->e_sqgids = (int *) xmalloc(n * sizeof(int)); + memcpy(dst->e_sqgids, src->e_sqgids, n * sizeof(int)); + } +} + +struct exportent * +mkexportent(char *hname, char *path, char *options) +{ + static struct exportent ee; + + ee.e_flags = EXPORT_DEFAULT_FLAGS; + ee.e_maptype = CLE_MAP_IDENT; + ee.e_anonuid = -2; + ee.e_anongid = -2; + ee.e_squids = NULL; + ee.e_sqgids = NULL; + ee.e_nsquids = 0; + ee.e_nsqgids = 0; + + if (strlen(hname) >= sizeof(ee.e_hostname)) { + xlog(L_WARNING, "client name %s too long", hname); + return NULL; + } + strncpy(ee.e_hostname, hname, sizeof (ee.e_hostname) - 1); + ee.e_hostname[sizeof (ee.e_hostname) - 1] = '\0'; + if (strlen(path) >= sizeof(ee.e_path)) { + xlog(L_WARNING, "path name %s too long", path); + return NULL; + } + strncpy(ee.e_path, path, sizeof (ee.e_path)); + ee.e_path[sizeof (ee.e_path) - 1] = '\0'; + strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1); + ee.m_path [sizeof (ee.m_path) - 1] = '\0'; + if (options && parseopts(options, &ee) < 0) + return NULL; + return ⅇ +} + +int +updateexportent(struct exportent *eep, char *options) +{ + if (options && parseopts(options, eep) < 0) + return 0; + return 1; +} + +/* + * Parse option string pointed to by s and set mount options accordingly. + */ +static int +parseopts(char *cp, struct exportent *ep) +{ + char *opt; + + squids = ep->e_squids; nsquids = ep->e_nsquids; + sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids; + + while (isblank(*cp)) + cp++; + while (*cp) { + opt = cp; + while (*cp && *cp != ',') + cp++; + if (*cp) + *cp++ = '\0'; + + /* process keyword */ + if (strcmp(opt, "ro") == 0) + ep->e_flags |= NFSEXP_READONLY; + else if (strcmp(opt, "rw") == 0) + ep->e_flags &= ~NFSEXP_READONLY; + else if (!strcmp(opt, "secure")) + ep->e_flags &= ~NFSEXP_INSECURE_PORT; + else if (!strcmp(opt, "insecure")) + ep->e_flags |= NFSEXP_INSECURE_PORT; + else if (!strcmp(opt, "sync")) + ep->e_flags &= ~NFSEXP_ASYNC; + else if (!strcmp(opt, "async")) + ep->e_flags |= NFSEXP_ASYNC; + else if (!strcmp(opt, "wdelay")) + ep->e_flags |= NFSEXP_GATHERED_WRITES; + else if (!strcmp(opt, "no_wdelay")) + ep->e_flags &= ~NFSEXP_GATHERED_WRITES; + else if (strcmp(opt, "root_squash") == 0) + ep->e_flags |= NFSEXP_ROOTSQUASH; + else if (!strcmp(opt, "no_root_squash")) + ep->e_flags &= ~NFSEXP_ROOTSQUASH; + else if (strcmp(opt, "all_squash") == 0) + ep->e_flags |= NFSEXP_ALLSQUASH; + else if (strcmp(opt, "no_all_squash") == 0) + ep->e_flags &= ~NFSEXP_ALLSQUASH; + else if (strncmp(opt, "mapping=", 8) == 0) + ep->e_maptype = parsemaptype(opt+8); + else if (strcmp(opt, "map_identity") == 0) /* old style */ + ep->e_maptype = CLE_MAP_IDENT; + else if (strcmp(opt, "map_daemon") == 0) /* old style */ + ep->e_maptype = CLE_MAP_UGIDD; + else if (strncmp(opt, "anonuid=", 8) == 0) + ep->e_anonuid = atoi(opt+8); + else if (strncmp(opt, "anongid=", 8) == 0) + ep->e_anongid = atoi(opt+8); + else if (strncmp(opt, "squash_uids=", 12) == 0) { + if (parsesquash(opt+12, &squids, &nsquids, &cp) < 0) + return -1; + } else if (strncmp(opt, "squash_gids=", 12) == 0) { + if (parsesquash(opt+12, &sqgids, &nsqgids, &cp) < 0) + return -1; + } else { + xlog(L_ERROR, + "Unknown keyword \"%s\" in export file\n", + opt); + ep->e_flags |= NFSEXP_ALLSQUASH | NFSEXP_READONLY; + return -1; + } + while (isblank(*cp)) + cp++; + } + + ep->e_squids = squids; + ep->e_sqgids = sqgids; + ep->e_nsquids = nsquids; + ep->e_nsqgids = nsqgids; + + return 1; +} + +static int +parsesquash(char *list, int **idp, int *lenp, char **ep) +{ + char *cp = list; + int id0, id1; + int len = *lenp; + int *id = *idp; + + if (**ep) + *--(*ep) = ','; + + do { + id0 = parsenum(&cp); + if (*cp == '-') { + cp++; + id1 = parsenum(&cp); + } else { + id1 = id0; + } + if (id0 == -1 || id1 == -1) { + syntaxerr("uid/gid -1 not permitted"); + return -1; + } + if ((len % 8) == 0) + id = (int *) xrealloc(id, (len + 8) * sizeof(*id)); + id[len++] = id0; + id[len++] = id1; + if (!*cp || *cp == ')' || (*cp == ',' && !isdigit(cp[1]))) + break; + if (*cp != ',') { + syntaxerr("bad uid/gid list"); + return -1; + } + cp++; + } while(1); + + if (*cp == ',') *ep = cp+1; + + *lenp = len; + *idp = id; + return 1; +} + +static void +freesquash(void) +{ + if (squids) { + xfree (squids); + squids = NULL; + nsquids = 0; + } + if (sqgids) { + xfree (sqgids); + sqgids = NULL; + nsqgids = 0; + } +} + +static int +parsenum(char **cpp) +{ + char *cp = *cpp, c; + int num = 0; + + if (**cpp == '-') + (*cpp)++; + while (isdigit(**cpp)) + (*cpp)++; + c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c; + return num; +} + +static int +parsemaptype(char *type) +{ + if (!strcmp(type, "identity")) + return CLE_MAP_IDENT; + if (!strcmp(type, "ugidd")) + return CLE_MAP_UGIDD; + if (!strcmp(type, "file")) + return CLE_MAP_FILE; + syntaxerr("invalid map type"); + return CLE_MAP_IDENT; /* default */ +} + +static int +getpath(char *path, int len) +{ + xskip(efp, " \t\n"); + return xgettok(efp, 0, path, len); +} + +static int +getexport(char *exp, int len) +{ + int ok; + + xskip(efp, " \t"); + if ((ok = xgettok(efp, 0, exp, len)) < 0) + xlog(L_ERROR, "error parsing export entry"); + return ok; +} + +static void +syntaxerr(char *msg) +{ + xlog(L_ERROR, "syntax error in exports file (line %d): %s", + efp->x_line, msg); +} + diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c new file mode 100644 index 0000000..5a6f1a4 --- /dev/null +++ b/support/nfs/getfh.c @@ -0,0 +1,55 @@ +/* + * support/nfs/getfh.c + * + * Get the FH for a given client and directory. This function takes + * the NFS protocol version number as an additional argument. + * + * This function has nothing in common with the SunOS getfh function, + * which is a front-end to the RPC mount call. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <string.h> +#include <sys/types.h> +#include <errno.h> +#include "nfslib.h" + +struct knfs_fh * +getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino) +{ + static union nfsctl_res res; + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + arg.ca_getfh.gf_version = 2; /* obsolete */ + arg.ca_getfh.gf_dev = dev; + arg.ca_getfh.gf_ino = ino; + memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in)); + + if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0) + return NULL; + + return &res.cr_getfh; +} + +struct knfs_fh * +getfh(struct sockaddr *addr, const char *path) +{ + static union nfsctl_res res; + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + arg.ca_getfd.gd_version = 2; /* obsolete */ + strncpy(arg.ca_getfd.gd_path, path, + sizeof(arg.ca_getfd.gd_path) - 1); + arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0'; + memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in)); + + if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0) + return NULL; + + return &res.cr_getfh; +} diff --git a/support/nfs/keytab.c b/support/nfs/keytab.c new file mode 100644 index 0000000..e33dded --- /dev/null +++ b/support/nfs/keytab.c @@ -0,0 +1,129 @@ +/* + * support/nfs/keytab.c + * + * Manage the nfskeys database. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> +#include "xmalloc.h" +#include "nfslib.h" +#include "exportfs.h" +#include "xio.h" + +static FILE *cfp = NULL; + +int +setnfskeyent(char *fname) +{ + if (cfp) + fclose(cfp); + if (!fname) + fname = _PATH_NFSKEYS; + cfp = fsetnfskeyent(fname, "r"); + return cfp != NULL; +} + +FILE * +fsetnfskeyent(char *fname, char *type) +{ +#if 0 + FILE *fp; + + if ((fp = fopen(fname, type)) == NULL) + xlog(L_ERROR, "can't open %s for %sing\n", + fname, type[0] == 'r'? "read" : "writ"); + return fp; +#else + return fopen(fname, type); +#endif +} + +struct nfskeyent * +getnfskeyent(void) +{ + return fgetnfskeyent(cfp); +} + +struct nfskeyent * +fgetnfskeyent(FILE *fp) +{ + static struct nfskeyent ke; + + if (!fp) + return NULL; + + do { + if (fread(&ke, sizeof(ke), 1, fp) != 1) + return NULL; + } while(ke.k_hostname[0] == '\0'); + return &ke; +} + +void +endnfskeyent(void) +{ + if (cfp) + fclose(cfp); + cfp = NULL; +} + +void +fendnfskeyent(FILE *fp) +{ + if (fp) + fclose(fp); +} + +void +fputnfskeyent(FILE *fp, struct nfskeyent *kep) +{ + fwrite(kep, sizeof(*kep), 1, fp); +} + +int +getnfskeytype(char *st) +{ + if (!strcasecmp(st, "null")) + return CLE_KEY_NULL; + if (!strcasecmp(st, "md5")) + return CLE_KEY_MD5; + if (!strcasecmp(st, "sha")) + return CLE_KEY_SHA; + return CLE_KEY_NONE; +} + +char * +getnfskeyname(int type) +{ + switch (type) { + case CLE_KEY_NONE: + return "none"; + case CLE_KEY_NULL: + return "null"; + case CLE_KEY_MD5: + return "md5"; + case CLE_KEY_SHA: + return "sha"; + } + return "unk"; +} + +int +getnfskeysize(int type) +{ + switch (type) { + case CLE_KEY_MD5: + return 16; + case CLE_KEY_SHA: + return 20; + } + return 0; +} diff --git a/support/nfs/lockdsvc.c b/support/nfs/lockdsvc.c new file mode 100644 index 0000000..532e721 --- /dev/null +++ b/support/nfs/lockdsvc.c @@ -0,0 +1,20 @@ +/* + * support/nfs/nfssvc.c + * + * Run an NFS daemon. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include "nfslib.h" + +int +lockdsvc() +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + return nfsctl(LOCKDCTL_SVC, &arg, NULL); +} diff --git a/support/nfs/nfsclient.c b/support/nfs/nfsclient.c new file mode 100644 index 0000000..5886484 --- /dev/null +++ b/support/nfs/nfsclient.c @@ -0,0 +1,32 @@ +/* + * support/nfs/client.c + * + * Add or delete an NFS client in knfsd. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <string.h> +#include "nfslib.h" + +int +nfsaddclient(struct nfsctl_client *clp) +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + memcpy(&arg.ca_client, clp, sizeof(arg.ca_client)); + return nfsctl(NFSCTL_ADDCLIENT, &arg, NULL); +} + +int +nfsdelclient(struct nfsctl_client *clp) +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + memcpy(&arg.ca_client, clp, sizeof(arg.ca_client)); + return nfsctl(NFSCTL_DELCLIENT, &arg, NULL); +} diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c new file mode 100644 index 0000000..c04588f --- /dev/null +++ b/support/nfs/nfsctl.c @@ -0,0 +1,24 @@ +/* + * support/nfs/nfsctl.c + * + * Central syscall to the nfsd kernel module. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <unistd.h> +#include <asm/unistd.h> +#include "nfslib.h" + +/* compatibility hack... */ +#ifndef __NR_nfsctl +#define __NR_nfsctl __NR_nfsservctl +#endif + +int +nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp) +{ + return syscall (__NR_nfsctl, cmd, argp, resp); +} diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c new file mode 100644 index 0000000..ce8b867 --- /dev/null +++ b/support/nfs/nfsexport.c @@ -0,0 +1,32 @@ +/* + * support/nfs/export.c + * + * Add or delete an NFS export in knfsd. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <string.h> +#include "nfslib.h" + +int +nfsexport(struct nfsctl_export *exp) +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + memcpy(&arg.ca_export, exp, sizeof(arg.ca_export)); + return nfsctl(NFSCTL_EXPORT, &arg, NULL); +} + +int +nfsunexport(struct nfsctl_export *exp) +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + memcpy(&arg.ca_export, exp, sizeof(arg.ca_export)); + return nfsctl(NFSCTL_UNEXPORT, &arg, NULL); +} diff --git a/support/nfs/nfssvc.c b/support/nfs/nfssvc.c new file mode 100644 index 0000000..7419baf --- /dev/null +++ b/support/nfs/nfssvc.c @@ -0,0 +1,22 @@ +/* + * support/nfs/nfssvc.c + * + * Run an NFS daemon. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include "nfslib.h" + +int +nfssvc(int port, int nrservs) +{ + struct nfsctl_arg arg; + + arg.ca_version = NFSCTL_VERSION; + arg.ca_svc.svc_nthreads = nrservs; + arg.ca_svc.svc_port = port; + return nfsctl(NFSCTL_SVC, &arg, NULL); +} diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c new file mode 100644 index 0000000..b9b5ff1 --- /dev/null +++ b/support/nfs/rmtab.c @@ -0,0 +1,122 @@ +/* + * support/nfs/rmtab.c + * + * Handling for rmtab. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <sys/fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include "nfslib.h" + +static FILE *rmfp = NULL; + +int +setrmtabent(char *type) +{ + if (rmfp) + fclose(rmfp); + rmfp = fsetrmtabent(_PATH_RMTAB, type); + return (rmfp != NULL); +} + +FILE * +fsetrmtabent(char *fname, char *type) +{ + int readonly = !strcmp(type, "r"); + FILE *fp; + + if (!fname) + return NULL; + if ((fp = fopen(fname, type)) == NULL) { + xlog(L_ERROR, "can't open %s for %sing", fname, + readonly ? "read" : "writ"); + return NULL; + } + return fp; +} + +struct rmtabent * +getrmtabent(int log) +{ + return fgetrmtabent(rmfp, log); +} + +struct rmtabent * +fgetrmtabent(FILE *fp, int log) +{ + static struct rmtabent re; + char buf[2048], *sp; + + errno = 0; + if (!fp) + return NULL; + do { + if (fgets(buf, sizeof(buf)-1, fp) == NULL) + return NULL; + if ((sp = strchr(buf, '\n')) != NULL) + *sp = '\0'; + if (!(sp = strchr(buf, ':'))) { + if (log) + xlog(L_ERROR, "malformed entry in rmtab file"); + errno = EINVAL; + return NULL; + } + *sp++ = '\0'; + } while (0); + strncpy(re.r_client, buf, sizeof (re.r_client) - 1); + re.r_client[sizeof (re.r_client) - 1] = '\0'; + strncpy(re.r_path, sp, sizeof (re.r_path) - 1); + re.r_path[sizeof (re.r_path) - 1] = '\0'; + return &re; +} + +void +putrmtabent(struct rmtabent *rep) +{ + fputrmtabent(rmfp, rep); +} + +void +fputrmtabent(FILE *fp, struct rmtabent *rep) +{ + if (!fp) + return; + fprintf(fp, "%s:%s\n", rep->r_client, rep->r_path); +} + +void +endrmtabent(void) +{ + fendrmtabent(rmfp); + rmfp = NULL; +} + +void +fendrmtabent(FILE *fp) +{ + if (fp) + fclose(fp); +} + +void +rewindrmtabent(void) +{ + if (rmfp) + rewind(rmfp); +} + +void +frewindrmtabent(FILE *fp) +{ + if (fp) + rewind (fp); +} diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c new file mode 100644 index 0000000..e798ea5 --- /dev/null +++ b/support/nfs/rpcdispatch.c @@ -0,0 +1,112 @@ +/* + * support/nfs/rcpdispatch.c + * + * Generic RPC dispatcher. + * + * Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <signal.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include "rpcmisc.h" +#include "xlog.h" + +void +rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp, + struct rpc_dtable *dtable, int nvers, + void *argp, void *resp) +{ + struct rpc_dentry *dent; + + if (rqstp->rq_vers > nvers) { + svcerr_progvers(transp, 1, nvers); + return; + } + dtable += (rqstp->rq_vers - 1); + if (rqstp->rq_proc > dtable->nproc) { + svcerr_noproc(transp); + return; + } + + dent = dtable->entries + rqstp->rq_proc; + + if (dent->func == NULL) { + svcerr_noproc(transp); + return; + } + + memset(argp, 0, dent->xdr_arg_size); + memset(resp, 0, dent->xdr_res_size); + + if (!svc_getargs(transp, dent->xdr_arg_fn, argp)) { + svcerr_decode(transp); + return; + } + + if ((dent->func)(rqstp, argp, resp) && resp != 0) { + if (!svc_sendreply(transp, dent->xdr_res_fn, (caddr_t)resp)) + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, dent->xdr_arg_fn, argp)) { + xlog(L_ERROR, "failed to free RPC arguments"); + exit (2); + } +} + +#if 0 +/* + * This is our replacement for svc_run. It turns off some signals while + * executing the server procedures to avoid nasty race conditions. + */ +void +rpc_svcrun(fd_set *morefds, void (*func)(int fd)) +{ + sigset_t block, current; + fd_set readfds; + + for (;;) { + readfds = svc_fdset; + if (morefds) { + int i; + + /* most efficient */ + for (i = 0; i < FD_SETSIZE; i++) + if (FD_ISSET(i, morefds)) + FD_SET(i, &readfs); + } + switch (select(FD_SETSIZE, &readfds, NULL, NULL, NULL)) { + case -1: + if (errno == EINTR) + continue; + xlog(L_ERROR, "svc_run: - select failed"); + break; + case 0: + continue; + default: + if (morefds) { + int i; + + /* most efficient */ + for (i = 0; i < FD_SETSIZE; i++) + if (FD_ISSET(i, morefds) && + FD_ISSET(i, &readfds)) + func(i); + } + sigemptyset(&block); + sigaddset(&block, SIGALRM); + sigaddset(&block, SIGVTALRM); + sigaddset(&block, SIGIO); + sigprocmask(SIG_BLOCK, &block, ¤t); + svc_getreqset(&readfds); + sigprocmask(SIG_SETMASK, ¤t, NULL); + } + } +} +#endif diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c new file mode 100644 index 0000000..7b182fd --- /dev/null +++ b/support/nfs/rpcmisc.c @@ -0,0 +1,230 @@ +/* + * support/nfs/rpcmisc.c + * + * Miscellaneous functions for RPC startup and shutdown. + * This code is partially snarfed from rpcgen -s tcp -s udp, + * partly written by Mark Shand, Donald Becker, and Rick + * Sladkey. It was tweaked slightly by Olaf Kirch to be + * usable by both unfsd and mountd. + * + * This software may be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <fcntl.h> +#include <memory.h> +#include <errno.h> +#include <unistd.h> +#include "nfslib.h" + +static void closedown(int sig); +static int makesock(int port, int proto, int socksz); + +#define _RPCSVC_CLOSEDOWN 120 +int _rpcpmstart = 0; +int _rpcfdtype = 0; +int _rpcsvcdirty = 0; + +void +rpc_init(char *name, int prog, int vers, void (*dispatch)(), int defport, + int bufsiz) +{ + struct sockaddr_in saddr; + SVCXPRT *transp; + int sock; + int asize; + + asize = sizeof(saddr); + sock = 0; + _rpcfdtype = 0; + if (getsockname(0, (struct sockaddr *) &saddr, &asize) == 0) { + int ssize = sizeof (int); + if (saddr.sin_family != AF_INET) + xlog(L_FATAL, "init: stdin is bound to non-inet addr"); + if (getsockopt(0, SOL_SOCKET, SO_TYPE, + (char *)&_rpcfdtype, &ssize) == -1) + xlog(L_FATAL, "getsockopt failed: %s", strerror(errno)); + _rpcpmstart = 1; + } else { + pmap_unset(prog, vers); + sock = RPC_ANYSOCK; + } + + if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { + if (_rpcfdtype == 0 && defport != 0 && + ((sock = makesock(defport, IPPROTO_UDP, bufsiz)) < 0)) { + xlog(L_FATAL, "%s: could not make a UDP socket\n", + name); + } + transp = svcudp_create(sock); + if (transp == NULL) { + xlog(L_FATAL, "cannot create udp service."); + } + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_UDP)) { + xlog(L_FATAL, "unable to register (%s, %d, udp).", + name, vers); + } + } + + if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { + if (_rpcfdtype == 0 && defport != 0 && + ((sock = makesock(defport, IPPROTO_TCP, bufsiz)) < 0)) { + xlog(L_FATAL, "%s: could not make a TCP socket\n", + name); + } + transp = svctcp_create(sock, 0, 0); + if (transp == NULL) { + xlog(L_FATAL, "cannot create tcp service."); + } + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_TCP)) { + xlog(L_FATAL, "unable to register (%s, %d, tcp).", + name, vers); + } + } + + if (_rpcpmstart) { + signal (SIGALRM, closedown); + alarm (_RPCSVC_CLOSEDOWN); + } +} + +static void closedown(sig) +int sig; +{ + (void) signal(sig, closedown); + if (_rpcsvcdirty == 0) { + extern fd_set svc_fdset; + static int size; + int i, openfd; + + if (_rpcfdtype == SOCK_DGRAM) + exit(0); + if (size == 0) { + size = getdtablesize(); + } + for (i = 0, openfd = 0; i < size && openfd < 2; i++) + if (FD_ISSET(i, &svc_fdset)) + openfd++; + if (openfd <= 1) + exit(0); + } + (void) alarm(_RPCSVC_CLOSEDOWN); +} + +static int makesock(port, proto, socksz) +int port; +int proto; +int socksz; +{ + struct sockaddr_in sin; + int s; + int sock_type; + int val; + + sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM; + s = socket(AF_INET, sock_type, proto); + if (s < 0) { + xlog(L_FATAL, "Could not make a socket: %s\n", + strerror(errno)); + return (-1); + } + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(port); + + val = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) + xlog(L_ERROR, "setsockopt failed: %s\n", strerror(errno)); + +#ifdef SO_SNDBUF + { + int sblen, rblen; + + /* 1024 for rpc & transport overheads */ + sblen = rblen = socksz + 1024; + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 || + setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0) + xlog(L_ERROR, "setsockopt failed: %s\n", strerror(errno)); + } +#endif /* SO_SNDBUF */ + + if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { + xlog(L_FATAL, "Could not bind name to socket: %s\n", + strerror(errno)); + return (-1); + } + return (s); +} + + +/* Log an incoming call. */ +void +rpc_logcall(struct svc_req *rqstp, char *xname, char *arg) +{ + char buff[1024]; + int buflen=sizeof(buff); + int len; + char *sp; + int i; + + if (!xlog_enabled(D_CALL)) + return; + + sp = buff; + switch (rqstp->rq_cred.oa_flavor) { + case AUTH_NULL: + sprintf(sp, "NULL"); + break; + case AUTH_UNIX: { + struct authunix_parms *unix_cred; + struct tm *tm; + + unix_cred = (struct authunix_parms *) rqstp->rq_clntcred; + tm = localtime(&unix_cred->aup_time); + snprintf(sp, buflen, "UNIX %d/%d/%d %02d:%02d:%02d %s %d.%d", + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + unix_cred->aup_machname, + unix_cred->aup_uid, + unix_cred->aup_gid); + sp[buflen-1] = 0; + len = strlen(sp); + sp += buflen; + buflen -= len; + if ((int) unix_cred->aup_len > 0) { + snprintf(sp, buflen, "+%d", unix_cred->aup_gids[0]); + sp[buflen-1] = 0; + len = strlen(sp); + sp += buflen; + buflen -= len; + for (i = 1; i < unix_cred->aup_len; i++) { + snprintf(sp, buflen, ",%d", + unix_cred->aup_gids[i]); + sp[buflen-1] = 0; + len = strlen(sp); + sp += buflen; + buflen -= len; + } + } + } + break; + default: + sprintf(sp, "CRED %d", rqstp->rq_cred.oa_flavor); + } + xlog(D_CALL, "%s [%s]\n\t%s\n", xname, buff, arg); +} diff --git a/support/nfs/wildmat.c b/support/nfs/wildmat.c new file mode 100644 index 0000000..8f7b760 --- /dev/null +++ b/support/nfs/wildmat.c @@ -0,0 +1,177 @@ +/* $Revision: 0.2.18.1 $ +** +** Do shell-style pattern matching for ?, \, [], and * characters. +** Might not be robust in face of malformed patterns; e.g., "foo[a-" +** could cause a segmentation violation. It is 8bit clean. +** +** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. +** Rich $alz is now <rsalz@osf.org>. +** April, 1991: Replaced mutually-recursive calls with in-line code +** for the star character. +** +** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code. +** This can greatly speed up failing wildcard patterns. For example: +** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* +** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 +** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 +** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without +** the ABORT code, it takes 22310 calls to fail. Ugh. The following +** explanation is from Lars: +** The precondition that must be fulfilled is that DoMatch will consume +** at least one character in text. This is true if *p is neither '*' nor +** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic +** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With +** FALSE, each star-loop has to run to the end of the text; with ABORT +** only the last one does. +** +** Once the control of one instance of DoMatch enters the star-loop, that +** instance will return either TRUE or ABORT, and any calling instance +** will therefore return immediately after (without calling recursively +** again). In effect, only one star-loop is ever active. It would be +** possible to modify the code to maintain this context explicitly, +** eliminating all recursive calls at the cost of some complication and +** loss of clarity (and the ABORT stuff seems to be unclear enough by +** itself). I think it would be unwise to try to get this into a +** released version unless you have a good test data base to try it out +** on. +*/ + +#include "config.h" + +#include <ctype.h> + +#define TRUE 1 +#define FALSE 0 +#define ABORT -1 + + + /* What character marks an inverted character class? */ +#define NEGATE_CLASS '^' + /* Is "*" a common pattern? */ +#define OPTIMIZE_JUST_STAR + /* Do tar(1) matching rules, which ignore a trailing slash? */ +#undef MATCH_TAR_PATTERN + + +/* +** Match text and p, return TRUE, FALSE, or ABORT. +*/ +static int +DoMatch(text, p) + register char *text; + register char *p; +{ + register int last; + register int matched; + register int reverse; + + for ( ; *p; text++, p++) { + if (*text == '\0' && *p != '*') + return ABORT; + switch (*p) { + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if (toupper (*text) != toupper (*p)) + return FALSE; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while (*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if (*p == '\0') + /* Trailing star matches everything. */ + return TRUE; + while (*text) + if ((matched = DoMatch(text++, p)) != FALSE) + return matched; + return ABORT; + case '[': + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; + if (reverse) + /* Inverted character class. */ + p++; + matched = FALSE; + if (p[1] == ']' || p[1] == '-') + if (toupper (*++p) == toupper(*text)) + matched = TRUE; + for (last = *p; *++p && *p != ']'; last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' && p[1] != ']' + ? *text <= *++p && *text >= last + : toupper (*text) == toupper (*p)) + matched = TRUE; + if (matched == reverse) + return FALSE; + continue; + } + } + +#ifdef MATCH_TAR_PATTERN + if (*text == '/') + return TRUE; +#endif /* MATCH_TAR_ATTERN */ + return *text == '\0'; +} + + +/* +** User-level routine. Returns TRUE or FALSE. +*/ +int +wildmat(text, p) + char *text; + char *p; +{ +#ifdef OPTIMIZE_JUST_STAR + if (p[0] == '*' && p[1] == '\0') + return TRUE; +#endif /* OPTIMIZE_JUST_STAR */ + return DoMatch(text, p) == TRUE; +} + + + +#if defined(TEST) +#include <stdio.h> + +/* Yes, we use gets not fgets. Sue me. */ +extern char *gets(); + + +int +main() +{ + char p[80]; + char text[80]; + + printf("Wildmat tester. Enter pattern, then strings to test.\n"); + printf("A blank line gets prompts for a new pattern; a blank pattern\n"); + printf("exits the program.\n"); + + for ( ; ; ) { + printf("\nEnter pattern: "); + (void)fflush(stdout); + if (gets(p) == NULL || p[0] == '\0') + break; + for ( ; ; ) { + printf("Enter text: "); + (void)fflush(stdout); + if (gets(text) == NULL) + exit(0); + if (text[0] == '\0') + /* Blank line; go back and get a new pattern. */ + break; + printf(" %s\n", wildmat(text, p) ? "YES" : "NO"); + } + } + + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/support/nfs/xio.c b/support/nfs/xio.c new file mode 100644 index 0000000..1bcd41b --- /dev/null +++ b/support/nfs/xio.c @@ -0,0 +1,151 @@ +/* + * support/nfs/xio.c + * + * Simple I/O functions for the parsing of /etc/exports and /etc/nfsclients. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <sys/fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <signal.h> +#include <unistd.h> +#include "xmalloc.h" +#include "xlog.h" +#include "xio.h" + +XFILE * +xfopen(char *fname, char *type) +{ + XFILE *xfp; + FILE *fp; + + if (!(fp = fopen(fname, type))) + return NULL; + xfp = (XFILE *) xmalloc(sizeof(*xfp)); + xfp->x_fp = fp; + xfp->x_line = 0; + + return xfp; +} + +void +xfclose(XFILE *xfp) +{ + fclose(xfp->x_fp); + xfree(xfp); +} + +static void +doalarm(int sig) +{ + return; +} + +int +xflock(char *fname, char *type) +{ + struct sigaction sa, oldsa; + int readonly = !strcmp(type, "r"); + struct flock fl = { readonly? F_RDLCK : F_WRLCK, SEEK_SET, 0, 0, 0 }; + int fd; + + if ((fd = open(fname, readonly? O_RDONLY : O_RDWR)) < 0) { + xlog(L_WARNING, "could not open %s for locking", fname); + return -1; + } + sa.sa_handler = doalarm; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGALRM, &sa, &oldsa); + alarm(10); + if (fcntl(fd, F_SETLKW, &fl) < 0) { + alarm(0); + xlog(L_WARNING, "failed to lock %s", fname); + close(fd); + fd = 0; + } else { + alarm(0); + } + sigaction(SIGALRM, &oldsa, NULL); + + return fd; +} + +void +xfunlock(int fd) +{ + close(fd); +} + +int +xgettok(XFILE *xfp, char sepa, char *tok, int len) +{ + int i = 0; + char c = 0; + + while (i < len && (c = xgetc(xfp)) != EOF && c != sepa && !isspace(c)) + tok[i++] = c; + if (c == '\n') + ungetc(c, xfp->x_fp); + if (!i) + return 0; + if (i >= len || (sepa && c != sepa)) + return -1; + tok[i] = '\0'; + return 1; +} + +char +xgetc(XFILE *xfp) +{ + char c = getc(xfp->x_fp); + + if (c == EOF) + return c; + if (c == '\\') { + if ((c = getc(xfp->x_fp)) != '\n') { + ungetc(c, xfp->x_fp); + return '\\'; + } + xfp->x_line++; + while ((c = getc(xfp->x_fp)) == ' ' || c == '\t'); + ungetc(c, xfp->x_fp); + return ' '; + } + if (c == '#') + c = xskipcomment(xfp); + if (c == '\n') + xfp->x_line++; + return c; +} + +void +xungetc(char c, XFILE *xfp) +{ + if (c != EOF) + ungetc(c, xfp->x_fp); +} + +void +xskip(XFILE *xfp, char *str) +{ + char c; + + while ((c = xgetc(xfp)) != EOF && strchr(str, c)); + ungetc(c, xfp->x_fp); +} + +char +xskipcomment(XFILE *xfp) +{ + char c; + + while ((c = getc(xfp->x_fp)) != EOF && c != '\n'); + return c; +} diff --git a/support/nfs/xlog.c b/support/nfs/xlog.c new file mode 100644 index 0000000..90c7e63 --- /dev/null +++ b/support/nfs/xlog.c @@ -0,0 +1,189 @@ +/* + * support/nfs/xlog.c + * + * This module handles the logging of requests. + * + * TODO: Merge the two "XXX_log() calls. + * + * Authors: Donald J. Becker, <becker@super.org> + * Rick Sladkey, <jrs@world.std.com> + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Olaf Kirch, <okir@monad.swb.de> + * + * This software maybe be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#include "config.h" + +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <syslog.h> +#include "nfslib.h" + +#undef VERBOSE_PRINTF + +static int foreground = 1; /* not a daemon initially */ +static int logging = 0; /* enable/disable DEBUG logs */ +static int logmask = 0; /* What will be logged */ +static char log_name[256]; /* name of this program */ +static int log_pid = -1; /* PID of this program */ +static FILE *log_fp = (FILE *)NULL; /* fp for the log file */ + +static void xlog_toggle(int sig); +static struct xlog_debugfac debugnames[] = { + { "general", D_GENERAL, }, + { "call", D_CALL, }, + { "auth", D_AUTH, }, + { "parse", D_PARSE, }, + { "all", D_ALL, }, + { NULL, 0, }, +}; + +void +xlog_open(char *progname) +{ + openlog(progname, LOG_PID, LOG_DAEMON); + if (foreground) { + log_fp = stderr; + if (log_fp != NULL) + setbuf(log_fp, NULL); + } + + strncpy(log_name, progname, sizeof (log_name) - 1); + log_name [sizeof (log_name) - 1] = '\0'; + log_pid = getpid(); + + signal(SIGUSR1, xlog_toggle); + signal(SIGUSR2, xlog_toggle); +} + +void +xlog_background(void) +{ + foreground = 0; +} + +static void +xlog_toggle(int sig) +{ + unsigned int tmp, i; + + if (sig == SIGUSR1) { + if ((logmask & D_ALL) && !logging) { + xlog(D_GENERAL, "turned on logging"); + logging = 1; + return; + } + tmp = ~logmask; + logmask |= ((logmask & D_ALL) << 1) | D_GENERAL; + for (i = -1, tmp &= logmask; tmp; tmp >>= 1, i++) + if (tmp & 1) + xlog(D_GENERAL, + "turned on logging level %d", i); + } else { + xlog(D_GENERAL, "turned off logging"); + logging = 0; + } + signal(sig, xlog_toggle); +} + +void +xlog_config(int fac, int on) +{ + if (on) + logmask |= fac; + else + logmask &= ~fac; + if (on) + logging = 1; +} + +void +xlog_sconfig(char *kind, int on) +{ + struct xlog_debugfac *tbl = debugnames; + + while (tbl->df_name != NULL && strcasecmp(tbl->df_name, kind)) + tbl++; + if (!tbl->df_name) { + xlog (L_WARNING, "Invalid debug facility: %s\n", kind); + return; + } + xlog_config(tbl->df_fac, on); +} + +int +xlog_enabled(int fac) +{ + return (logging && (fac & logmask)); +} + + +/* Write something to the system logfile. */ +void +xlog(int kind, const char *fmt, ...) +{ + char buff[1024]; + va_list args; + int logged = 1, n; +#ifdef VERBOSE_PRINTF + time_t now; + struct tm *tm; +#endif + + if (!(kind & (L_ALL)) && !(logging && (kind & logmask))) + return; + + va_start(args, fmt); + vsnprintf(buff, sizeof (buff), fmt, args); + va_end(args); + buff[sizeof (buff) - 1] = 0; + + if ((n = strlen(buff)) > 0 && buff[n-1] != '\n') { + buff[n++] = '\n'; buff[n++] = '\0'; + } + + switch (kind) { + case L_FATAL: + syslog(LOG_ERR, "%s", buff); + break; + case L_ERROR: + syslog(LOG_ERR, "%s", buff); + break; + case L_WARNING: + syslog(LOG_WARNING, "%s", buff); + break; + case L_NOTICE: + syslog(LOG_NOTICE, "%s", buff); + break; + default: + logged = 0; + break; + } + if (!logged || foreground) { + if (!logged && log_fp == NULL) { + syslog(LOG_DEBUG, "%s", buff); + } else if (log_fp != NULL) { +#ifdef VERBOSE_PRINTF + time(&now); + tm = localtime(&now); + fprintf(log_fp, "%s[%d] %02d/%02d/%02d %02d:%02d %s\n", + log_name, log_pid, + tm->tm_mon + 1, tm->tm_mday, + tm->tm_year, tm->tm_hour, tm->tm_min, + buff); +#else + fprintf(log_fp, "%s: %s", log_name, buff); +#endif + } + } + if (kind == L_FATAL) + exit(1); +} diff --git a/support/nfs/xmalloc.c b/support/nfs/xmalloc.c new file mode 100644 index 0000000..9523afc --- /dev/null +++ b/support/nfs/xmalloc.c @@ -0,0 +1,48 @@ +/* + * support/nfs/xmalloc.c + * + * malloc with NULL checking. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include "xmalloc.h" +#include "xlog.h" + +void * +xmalloc(size_t size) +{ + void *ptr; + + if (!(ptr = malloc(size))) + xlog(L_FATAL, "malloc: out of memory"); + return ptr; +} + +void * +xrealloc(void *ptr, size_t size) +{ + if (!(ptr = realloc(ptr, size))) + xlog(L_FATAL, "realloc: out of memory"); + return ptr; +} + +void +xfree(void *ptr) +{ + free(ptr); +} + +char * +xstrdup(const char *str) +{ + char *ret; + + if (!(ret = strdup(str))) + xlog(L_FATAL, "strdup: out of memory"); + return ret; +} diff --git a/support/nfs/ypupdate_xdr.c b/support/nfs/ypupdate_xdr.c new file mode 100644 index 0000000..9fe1098 --- /dev/null +++ b/support/nfs/ypupdate_xdr.c @@ -0,0 +1,29 @@ +/* + * support/nfs/ypupdate_xdr.c + * + * This file contains the XDR code for the ypupdate protocol. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#include "config.h" + +#include <ypupdate.h> + +bool_t +xdr_ypupdate_args(XDR *xdrs, ypupdate_args *objp) +{ + return xdr_string(xdrs, &objp->mapname, MAXMAPNAMELEN) && + xdr_bytes(xdrs, &objp->key.yp_buf_val, + &objp->key.yp_buf_len, MAXYPDATALEN) && + xdr_bytes(xdrs, &objp->datum.yp_buf_val, + &objp->datum.yp_buf_len, MAXYPDATALEN); +} + +bool_t +xdr_ypdelete_args(XDR *xdrs, ypdelete_args *objp) +{ + return xdr_string(xdrs, &objp->mapname, MAXMAPNAMELEN) && + xdr_bytes(xdrs, &objp->key.yp_buf_val, + &objp->key.yp_buf_len, MAXYPDATALEN); +} |