shand@cad.jmrc.eecs.unsw.oz (Mark Shand) (05/25/88)
Submitted by: shand@cad.jmrc.eecs.unsw.oz (Mark Shand) Posting-number: Volume 15, Issue 1 Archive-name: unfsd/Part01 [ Within the stated limitations, this seems to be a useful tool. It compiled and ran fine on my (slightly pre) 4.3bsd vax. Nb: you need the Sun RPC version 3.9 from Volume 13 or comp.sources.unix in order to use this submission. ..kre ] UNFSD - USER-LEVEL NFS SERVER ============================= This package implements a simple user level NFS server based on the sunrpc3.9 package that was posted to the net a few months ago. The current version only provides read access from the clients. It has been tested between a VAX11/780 running 4.3BSD (the server) and several diskful SUN3/60 running SunOS 3.4 (the clients) and on a diskless SUN3/50 running SunOS 3.2 remounting its own root at a lower level of its file hierarchy. #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-rw-r-- 1 shand 2392 May 17 01:59 Makefile # -rw-rw-r-- 1 shand 6087 May 18 21:30 README # -rw-r--r-- 1 shand 18021 May 17 02:24 fh.c # -rw-rw-r-- 1 shand 727 May 17 02:24 fh.h # -rw-rw-r-- 1 shand 9203 May 17 02:25 init.c # -rw-rw-r-- 1 shand 4310 May 16 02:24 mount.x # echo 'x - Makefile' if test -f Makefile; then echo 'shar: not overwriting Makefile'; else sed 's/^X//' << '________This_Is_The_END________' > Makefile X# For standard 4.3BSD systems with sunrpc3.9 installed X#LIB=-lrpclib X# For SunOS and other systems with rpc in the c library XLIB= X X# Client authorization file XEXPORTSFILE=/etc/unfsd_exports X X# Try -DDEBUG for a copious debug log to be written to /tmp/unfsd.log XCFLAGS= -O -DREAD_ONLY -DEXPORTSFILE='"${EXPORTSFILE}"' XLDFLAGS= -O X XRPCGEN= rpcgen XCC= cc X#------------------------------End of configuration section. X XNFSOBJS= nfs_prot_svc.o nfs_prot_xdr.o unfsd.o init.o \ X fh.o ugid_map.o ugid_xdr.o ugid_clnt.o X Xall: unfsd unfsmntd X Xinstall: unfsd unfsmntd X cp unfsd ${INSDIR}/unfsd X cp unfsmntd ${INSDIR}/unfsmntd X Xunfsd: ${NFSOBJS} X ${CC} $(LDFLAGS) -o unfsd ${NFSOBJS} ${LIB} X Xunfsmntd: mount_svc.o mount_xdr.o unfsmntd.o fh.o X ${CC} $(LDFLAGS) -o unfsmntd mount_svc.o mount_xdr.o unfsmntd.o fh.o ${LIB} X Xugidd: ugid_svc.o ugid_xdr.o ugidd.o X ${CC} $(LDFLAGS) -o ugidd ugid_svc.o ugid_xdr.o ugidd.o ${LIB} Xmprobe: mprobe.o mount_xdr.o nfs_prot_xdr.o X ${CC} ${LDFLAGS} -o mprobe mprobe.o mount_xdr.o nfs_prot_xdr.o \ X rpc/rpc/librpclib.a X Xnfs_prot.h: nfs_prot.x X ${RPCGEN} -h -o $@ $? X Xnfs_prot_svc.c: nfs_prot.x X ${RPCGEN} -s udp $? | \ X sed \ X -e 's/main()/main(argc,argv) int argc; char **argv;/' \ X -e 's/RPC_ANYSOCK/makesock(NFS_PORT, NFS_MAXDATA)/' \ X -e 's/svc_run();/unfsd_init(argc,argv); svc_run();/' \ X > $@ X Xnfs_prot_xdr.c: nfs_prot.x X ${RPCGEN} -c -o $@ $? X Xmount.h: mount.x X ${RPCGEN} -h -o $@ $? X Xmount_svc.c: mount.x X ${RPCGEN} -s udp $? | \ X sed \ X -e 's/main()/main(argc,argv) int argc; char **argv;/' \ X -e 's/svc_run();/unfsmntd_init(argc,argv); svc_run();/' \ X > $@ X Xmount_xdr.c: mount.x X ${RPCGEN} -c -o $@ $? X Xugid.h: ugid.x X ${RPCGEN} -h -o $@ $? X Xugid_svc.c: ugid.x X ${RPCGEN} -s udp $? | \ X sed \ X -e 's/main()/main(argc,argv) int argc; char **argv;/' \ X -e 's/RPC_ANYSOCK/run_mode_from_args(argc,argv)/' \ X > $@ X Xugid_xdr.c: ugid.x X ${RPCGEN} -c -o $@ $? X Xugid_clnt.c: ugid.x X ${RPCGEN} -l -o $@ $? Xclean: X rm -rf *.o nfs_prot_svc.c nfs_prot_xdr.c nfs_prot.h \ X mount_svc.c mount_xdr.c mount.h \ X ugid_svc.c ugid_xdr.c ugid_clnt.c ugid.h \ X unfsd unfsmntd ugidd mprobe X X# include dependencies Xnfs_prot_svc.o nfs_prot_xdr.o unfsd.o fh.o init.o: nfs_prot.h X Xmount_svc.o mount_xdr.o unfsmntd.o: mount.h X Xugid_map.o ugid_svc.o ugid_xdr.o ugidd.o unfsd.o init.o: ugid.h X Xmprobe.o: mount.h X Xfh.o unfsd.o: fh.h X Xunfsd.o ugid_map.o init.o: unfsd.h ________This_Is_The_END________ if test `wc -l < Makefile` -ne 97; then echo 'shar: Makefile was damaged during transit (should have been 97 bytes)' fi fi ; : end of overwriting check echo 'x - README' if test -f README; then echo 'shar: not overwriting README'; else sed 's/^X//' << '________This_Is_The_END________' > README XUNFSD - USER-LEVEL NFS SERVER X============================= X XThis package implements a simple user level NFS server based on the Xsunrpc3.9 package that was posted to the net a few months ago. The Xcurrent version only provides read access from the clients. It has Xbeen tested between a VAX11/780 running 4.3BSD (the server) and several Xdiskful SUN3/60 running SunOS 3.4 (the clients) and on a diskless XSUN3/50 running SunOS 3.2 remounting its own root at a lower level of Xits file hierarchy. X XThe server is implemented by two programs unfsd and unfsmntd. XUnfsmntd handles the mount protocol, and unfsd handles all subsequent Xoperations. X XCurrently NFS is defined to use internet port 2049. As a consequence Xthere can only be one implementation of NFS active on a given machine. XThus a machine cannot make it filesystem available through this server Xwhile concurrently running some alternate server implementation. X XNormally the server would be run by the super-user. I had hoped to be Xable to run the server as a normal user, and indeed the server contains Xcode to cope with paths containing directories that can be accessed but Xnot searched, however the sunrpc portmapper listens on port 111 so some Xsuperuser cooperation is required to at least gain support for sunrpc Xon sites running standard 4.3 BSD. X XUnlike SUN's NFS-servers, the file hierarchy exported by unfsd treats Xmount points within an exports filesystem transparently; thus the Xclient sees the same file hierarchy as is seen from the server. X XCOPYRIGHT X========= X XThese programs may be freely distributed provided they retain my Xcopyright notices. They are provided as is, with no warranty Xexpressed or implied. X XINSTALLATION X============ X X1. If you have installed Van Jacobson's TCP/IP code be sure you have X installed the fix I posted to comp.bugs.4bsd (reproduced below). X Otherwise UDP packets larger than the maximum IP fragment size of X your net will mysteriously fail. X X2. Edit the first few lines of the Makefile to reflect local conditions. X X3. If your client and server machines have different uid/username X mappings you may wish to run ugidd on the client (see below). X Otherwise the server assumes one-to-one correspondence between X uids and gids on the server. X X4. "make" and "make install". X X5. Create a /etc/unfsd_exports file to authorize clients of your server, X and set desired options (Note: options may also be set with the X command that starts the server see unfsd(8) and installation step 7). X X6. Run "unfsmntd" and "unfsd" and try to mount server file systems from X your authorized clients. X X7. Arrange for the server to be started at boot-time. EG in /etc/rc.local X add: X if [ -f /etc/unfsmntd ]; then X /etc/unfsmntd X fi X if [ -f /etc/unfsd ]; then X /etc/unfsd X fi X X8. Edit client fstabs to mount from the new server at boot-time. X XUGIDD X===== X XIf you have the same set of user group names on your client and server Xmachines but differing uids and gids you may wish to run the ugidd on Xthe clients and enable to server to map between local and remote ids Xusing this pprogram. Ugidd is a simple rpc-based service that supplies Xtranslations between names and uid/gids on the client. To guard against Xtrojan horses the ugidd authenicates itself by signalling the unfsd on Xa reserved internet port. X XTo install ugidd on a client: X X1. "make ugidd" and copy ugidd to standard place like /usr/etc/rpc.ugidd X X2. Either run it from /etc/rc.local with the command X /usr/etc/rpc.ugidd -d X or if using a version of inetd that supports sunrpc, invoke it X from inetd with the line X rpc udp /usr/etc/rpc.ugidd 545580417 1 X in /etc/servers (SunOS 3.x) or /etc/inetd.conf (4.3 BSD). X (See ugidd(8)). X X3. Set the "map_daemon" option for this client in the servers X /etc/unfsd_exports file. (See unfsd_exports(5)). X XNote: When ugidd fails to respond to a server, or the specified Xname (or uid/gid) has no corresponding uid/gid (or name), the Xserver assumes a mapping to the unprivelegded user "nobody" (uid: -2). X XTCP/IP FIX X========== X XHere follows a fix to the Van Jacobson TCP/IP upgrade. X XSubject: bug in new tcp/ip code X X[ posted to comp.bugs.4bsd Thu Apr 21 16:36:04 1988 ] X XThere is a bug in the upgrade of 4.3BSD networking code that was Xrecently posted to comp.bugs.4bsd.ucb-fixes. When an IP packet is Xtoo large for an interface and must therefore be fragmented, some of Xthe fields of the IP header in the first packet are not converted to Xnetwork byte-order. X XThe fix is as follows: X X*** /sys/netinet/ip_output.c.orig Tue Apr 12 15:52:46 1988 X--- /sys/netinet/ip_output.c Thu Apr 21 13:16:16 1988 X*************** X*** 232,239 **** X * and updating header, then send each fragment (in order). X */ X m_adj(m0, hlen + firstlen - ip->ip_len); X! ip->ip_len = hlen + firstlen; X! ip->ip_off |= IP_MF; X ip->ip_sum = 0; X ip->ip_sum = in_cksum(m0, hlen); X sendorfree: X--- 232,239 ---- X * and updating header, then send each fragment (in order). X */ X m_adj(m0, hlen + firstlen - ip->ip_len); X! ip->ip_len = htons((u_short)(hlen + firstlen)); X! ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); X ip->ip_sum = 0; X ip->ip_sum = in_cksum(m0, hlen); X sendorfree: X XSECURITY ISSUES X=============== X XWhen I first started looking at standard SunOS 3.x NFS I was pretty well Xappalled by the lack of security. I later found that Security could be Ximproved considerably it was just that the defaults were (in my opinion) Xwrong. By default, unfsd insists that NFS requests originate from a Xsecure port from a known internet address. X XUnfsd presumes that the kernel of the client deals correctly with access Xpermission checks. In my experience this seems to be true of SunOS 3.x Xkernels for read accesses across NFS, but not for write accesses. It is Xfor this reason that write accesses remain unimplemented in the current Xversion of the server. X X---------- X XMark Shand XJoint Microelectronics Research Centre XSchool of Electrical Engineering XUniversity of NSW XPO Box 1 XKensington XNSW 2033 XAUSTRALIA X X+61 2 697 4898 X Xshand@cad.jmrc.eecs.unsw.oz ________This_Is_The_END________ if test `wc -l < README` -ne 171; then echo 'shar: README was damaged during transit (should have been 171 bytes)' fi fi ; : end of overwriting check echo 'x - fh.c' if test -f fh.c; then echo 'shar: not overwriting fh.c'; else sed 's/^X//' << '________This_Is_The_END________' > fh.c X/* UNFSD - copyright Mark A Shand, May 1988. X * This software maybe be used for any purpose provided X * the above copyright notice is retained. It is supplied X * as is, with no warranty expressed or implied. X */ X X/* X * FILE HANDLE PACKAGE FOR USER-LEVEL NFS SERVER X * X * Interfaces: X * pseudo_inode X * mostly used internally, but also called from unfsd.c X * when reporting directory contents. X * fh_pr X * debugging primitive; converts file handle into a printable X * text string X * fh_create X * establishes initial file handle; called from mount daemon X * fh_path X * returns unix path corresponding to fh X * fh_fd X * returns open file descriptor for given file handle; X * provides caching of open files X * fd_idle X * provides mututal exclusion of normal file descriptor cache X * use, and alarm-driven cache flushing X * fh_compose X * construct new file handle from existing file handle and X * directory entry X * fh_psi X * returns pseudo_inode corresponding to file handle X */ X X#include <sys/param.h> X#include <sys/types.h> X#include <sys/file.h> X#include <sys/time.h> X#include <sys/stat.h> X#include <rpc/rpc.h> X#include <sys/dir.h> X#include <strings.h> X#include <errno.h> X#include <syslog.h> X X/* mask SUNOS/BSD4.3 syslog incompatibilities */ X#ifndef LOG_DAEMON X#define LOG_DAEMON 0 X#endif /* LOG_DAEMON */ X X#ifdef DEBUG X#include <stdio.h> XFILE *debuglog; X#endif DEBUG X X#include "nfs_prot.h" X X#include "fh.h" X X#define FHC_XONLY_PATH 01 X#define FHC_BUSY 02 /* NOT USED */ X X#define CACHE_SIZE_LIMIT 500 X#define LOWAT_CACHE_SIZE 3*CACHE_SIZE_LIMIT X#define HIWAT_CACHE_SIZE 4*CACHE_SIZE_LIMIT X#define HASH_TAB_SIZE (5*CACHE_SIZE_LIMIT | 03) X X/* X * Paths constructed in this system always consist of real directories X * (excepting the last element) i.e. they do not contain symbolic links. X * This is guaranteed by the way NFS constructs the paths. X * As a consequence we may assume that X * /x/y/z/.. == /x/y X * and /x/y/z/. == /x/y/z X * provided that z != . && z != .. X * These relations are exploited in fh_compose. X * X * Further assumptions: X * All cached pathnames consist of a leading / X * followed by zero or more / separated names X * s.t. X * name != . X * name != .. X * index(name, '/') == 0 X */ X Xtypedef struct fhcache X{ X struct fhcache *next; X struct fhcache *prev; X struct fhcache *hash_next; X svc_fh h; X int fd; X int omode; X char *path; X time_t last_used; X int flags; X} X fhcache; X Xstatic int path_psi(); Xstatic fhcache fh_head, fh_tail, *last_flushable; Xstatic fhcache *fh_hashed[HASH_TAB_SIZE]; Xstatic int fh_list_size; Xstatic time_t curtime; Xextern int errno; X Xstatic void Xfh_move_to_front(fhc) Xfhcache *fhc; X{ X /* Remove from current posn */ X fhc->prev->next = fhc->next; X fhc->next->prev = fhc->prev; X /* Insert at head */ X fhc->prev = &fh_head; X fhc->next = fh_head.next; X fhc->prev->next = fhc; X fhc->next->prev = fhc; X} X Xstatic void Xfh_inserthead(fhc) Xfhcache *fhc; X{ X fhcache **hash_slot; X X /* Insert at head */ X fhc->prev = &fh_head; X fhc->next = fh_head.next; X fhc->prev->next = fhc; X fhc->next->prev = fhc; X fh_list_size++; X X /* Insert into hash tab */ X hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]); X fhc->hash_next = *hash_slot; X *hash_slot = fhc; X} X Xstatic fhcache * Xfh_lookup(psi) Xu_long psi; X{ X fhcache *fhc; X fhc = fh_hashed[psi % HASH_TAB_SIZE]; X while (fhc != NULL && fhc->h.psi != psi) X fhc = fhc->hash_next; X return fhc; X} X Xstatic void Xfh_delete(fhc) Xfhcache *fhc; X{ X fhcache **hash_slot; X X /* Remove from current posn */ X fhc->prev->next = fhc->next; X fhc->next->prev = fhc->prev; X fh_list_size--; X X /* Remove from hash tab */ X hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]); X while (*hash_slot != NULL && *hash_slot != fhc) X hash_slot = &((*hash_slot)->hash_next); X if (*hash_slot == NULL) X syslog(LOG_DAEMON|LOG_WARNING, X "internal inconsistency -- fhc(%x) not in hash table", fhc); X else X *hash_slot = fhc->hash_next; X X /* Free storage */ X if (fhc->path != NULL) X { X#ifdef DEBUG X if (debuglog != NULL) X fprintf(debuglog, "flushing: %s\n", X fhc->path); X#endif DEBUG X free(fhc->path); X } X free(fhc); X} X X/* X * INODES and DEVICES. NFS assumes that each file within an NFS mounted X * file-system has a unique inode number. Thus to mount an entire file X * hierarchy, as this server sets out to do, requires mapping from inode/devs X * to pseudo-inode. Furthermore mount points must be detected and so that X * pseudo-inode("name") == pseudo-inode(direntry("name/../name")) X * One option is to force the directory entry inode to correspond to the X * result of the stat call, but this involves stat'ing every directory entry X * during a readdir. Instead we force the stat call to corresopnd to the X * directory entry inode (see inner_getattr). Of course this technique X * requires that the parent directory is readable. If it is not the normal X * stat call result is used. There is no chance of conflict because the X * directory can never be read. X * X * In theory unique pseudo-inodes cannot be guaranteed, since inode/dev X * contains 48 bits of information which must be crammed into an inode X * number constrained to 32 bits. Fortunately inodes numbers tend to be X * small (often < 64k, almost always < 512k) X */ X Xint Xpseudo_inode(inode,dev) Xu_long inode; Xu_short dev; X{ X register dmajor,dminor; X X /* Assuming major and minor numbers are small integers, X * gravitate bits of dmajor & dminor device number to X * high-order bits of word, to avoid clash with real inode num. X */ X /* reverse (byte-wise) */ X dmajor = ((dev & 0xf0f) << 4) | ((dev & 0xf0f0) >> 4); X dmajor = ((dmajor & 0x3333) << 2) | ((dmajor & 0xcccc) >> 2); X dmajor = ((dmajor & 0x5555) << 1) | ((dmajor & 0xaaaa) >> 1); X /* spread low-16 -> 32 with 0's in even posn */ X dmajor = ((dmajor & 0xff00) << 8) | (dmajor & 0xff); X dmajor = ((dmajor & 0xf000f0) << 4) | (dmajor & 0xf000f); X dmajor = ((dmajor & 0xc0c0c0c) << 2) | (dmajor & 0x3030303); X dmajor = ((dmajor & 0x22222222) << 1) | (dmajor & 0x11111111); X dminor = (dmajor & 0x5555) << 15; X dmajor = dmajor & 0x55550000; X X return (dmajor | dminor) ^ inode; X} X X#define hash_psi(psi) (((psi)^((psi)>>8)^((psi)>>16)^((psi)>>24)) & 0xff) X Xint Xmallocfailed() X{ X syslog(LOG_DAEMON|LOG_WARNING, "malloc failed -- exiting"); X exit(1); X} X X/* flush_cache() is invoked periodically from SIGALRM, and on X * demand from fh_find. A simple form of mutual exclusion X * protects this routine from multiple concurrent executions. X * Since the preemption that occurs when a signal is received X * is one-sided, we do need an atomic test and set. If the X * signal arrives between the test and the set, the first X * invocation safely stalls until the signal-caused invocation X * completes. X */ Xtypedef enum { idle, active } mutex; X Xstatic mutex ex_state = idle; X X/* The following affect execute-only directories */ X#define FLUSH_INTERVAL (60*60*12) /* Twice a day */ X#define BUSY_RETRY_INTERVAL (60*10) /* Ten minutes */ X#define DISCARD_INTERVAL (FLUSH_INTERVAL*2) /* Two days */ X Xstatic int Xflush_cache() X{ X fhcache *h; X X#ifdef DEBUG X if (debuglog != NULL) X { X long thing; X time(&thing); X fprintf(debuglog, "flushing cache at %s: state = %s\n", X ctime(&thing), X (ex_state == idle) ? "idle" : "active"); X } X#endif DEBUG X if (ex_state == idle) X { X int cache_size = 0; X X ex_state = active; X time(&curtime); X /* Single execution thread */ X /* discard old open files */ X fh_fd(NULL); X X /* works in empty case because: fh_tail.next = &fh_tail */ X h = fh_head.next->next; X while (h != &fh_tail) X { X if (cache_size > LOWAT_CACHE_SIZE X || (cache_size > CACHE_SIZE_LIMIT X && (h->flags & FHC_XONLY_PATH) == 0) X || curtime > h->last_used + DISCARD_INTERVAL) X { X h = h->next; X fh_delete(h->prev); X } X else X { X cache_size++; X h = h->next; X } X } X if (fh_list_size != cache_size) X syslog(LOG_DAEMON|LOG_WARNING, X "internal inconsistency (fh_list_size=%d) != (cache_size=%d)", X fh_list_size, cache_size); X fh_list_size = cache_size; X ex_state = idle; X signal(SIGALRM, flush_cache); X alarm(FLUSH_INTERVAL); X } X else X { X signal(SIGALRM, flush_cache); X alarm(BUSY_RETRY_INTERVAL); X } X} X Xvoid Xfh_init() X{ X fh_head.next = fh_tail.next = &fh_tail; X fh_head.prev = fh_tail.prev = &fh_head; X last_flushable = &fh_tail; X fh_tail.flags = FHC_XONLY_PATH; X signal(SIGALRM, flush_cache); X alarm(FLUSH_INTERVAL); X} X Xstatic char *fh_buildpath(); X Xstatic fhcache * Xfh_find(h, create) Xsvc_fh *h; Xint create; X{ X fhcache *fhc; X X ex_state = active; X time(&curtime); X while ((fhc = fh_lookup(h->psi)) != NULL) X { X /* but what if hash_paths are not the same? */ X /* Something is stale */ X if (bcmp(h->hash_path, fhc->h.hash_path, HP_LEN) != 0) X { X if (!create) X return NULL; X fh_delete(fhc); X break; X } X if (fhc != fh_head.next) X fh_move_to_front(fhc); X fhc->last_used = curtime; X ex_state = idle; X return fhc; X } X if (fh_list_size > CACHE_SIZE_LIMIT) X { X /* don't flush current head */ X while (last_flushable != fh_head.next) X { X if ((last_flushable->flags & FHC_XONLY_PATH) == 0) X { X fhc = last_flushable; X last_flushable = last_flushable->prev; X fh_delete(fhc); X break; X } X last_flushable = last_flushable->prev; X } X last_flushable = last_flushable->next; X } X if (create) X { X if ((fhc = (fhcache *) malloc(sizeof *fhc)) == NULL) X mallocfailed(); X fhc->path = NULL; X fhc->last_used = curtime; X fhc->h = *h; X fh_inserthead(fhc); X } X else X { X /* attempt to contruct from hash_path */ X char *path; X X if ((path = fh_buildpath(h)) == NULL) X return NULL; X if ((fhc = (fhcache *) malloc(sizeof *fhc)) == NULL) X mallocfailed(); X fhc->path = path; X fhc->fd = -1; X fhc->flags = 0; X fhc->last_used = curtime; X fhc->h = *h; X fh_inserthead(fhc); X } X ex_state = idle; X if (fh_list_size > HIWAT_CACHE_SIZE) X flush_cache(); X return fhc; X} X Xstatic char * Xfh_buildpath(h) Xsvc_fh *h; X{ X int i; X int psi; X char *path; X struct stat sbuf; X char pathbuf[MAXPATHLEN+MAXNAMLEN+1]; X long cookie_stack[HP_LEN+1]; X char *slash_stack[HP_LEN]; X X if (stat("/", &sbuf) < 0) X return NULL; X psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev); X if (h->hash_path[0] == 0) X { X if (psi != h->psi) X return NULL; X if ((path = malloc(2)) == NULL) X mallocfailed(); X strcpy(path, "/"); X return path; X } X /* else */ X if (hash_psi(psi) != h->hash_path[1]) X return NULL; X strcpy(pathbuf, "/"); X cookie_stack[2] = 0; X for (i = 2; i <= h->hash_path[0]+1; i++) X { X DIR *dir; X struct direct *dp; X X backtrack: X if (stat(pathbuf, &sbuf) >= 0 X && (dir = opendir(pathbuf)) != NULL) X { X if (cookie_stack[i] != 0) X seekdir(dir, cookie_stack[i]); X while (dp = readdir(dir)) X { X if (strcmp(dp->d_name, ".") != 0 X && strcmp(dp->d_name, "..") != 0) X { X psi = pseudo_inode(dp->d_ino, sbuf.st_dev); X if (i == h->hash_path[0]+1) X { X if (psi == h->psi) X { X /*GOT IT*/ X strcat(pathbuf, dp->d_name); X if ((path = malloc(strlen(pathbuf)+1)) == NULL) X mallocfailed(); X strcpy(path, pathbuf); X closedir(dir); X return path; X } X } X else X { X if (hash_psi(psi) == h->hash_path[i]) X { X /*PERHAPS WE'VE GOT IT */ X cookie_stack[i] = telldir(dir); X cookie_stack[i+1] = 0; X slash_stack[i] = pathbuf + strlen(pathbuf); X strcpy(slash_stack[i], dp->d_name); X strcat(pathbuf, "/"); X X closedir(dir); X goto deeper; X } X } X } X } X /* dp == NULL */ X closedir(dir); X } X else if (i <= h->hash_path[0] X && access(pathbuf, R_OK) != 0 X && access(pathbuf, X_OK) == 0) X { X /* Execute-only directory? Maybe its in the cache. */ X /* Note: cache is frozen for duration of fh_buildpath */ X svc_fh xh; X fhcache *fhc; X X xh = *h; X xh.hash_path[0] = i-1; X if (cookie_stack[i] == 0) X fhc = fh_head.next; X else X fhc = ((fhcache *)(cookie_stack[i]))->next; X while (fhc != &fh_tail) X if (bcmp(xh.hash_path, fhc->h.hash_path, i) == 0 X && xh.hash_path[i] == hash_psi(fhc->h.psi)) X break; X else X fhc = fhc->next; X if (fhc != NULL) X { X strcpy(pathbuf, fhc->path); X cookie_stack[i] = (long) fhc; X cookie_stack[i+1] = 0; X slash_stack[i] = rindex(pathbuf,'/')+1; X strcat(pathbuf, "/"); X goto deeper; X } X } X /* shallower */ X i--; X if (i < 2) X return NULL; /* SEARCH EXHAUSTED */ X /* Prune path */ X *(slash_stack[i]) = '\0'; X goto backtrack; X deeper: ; X } X return NULL; /* Actually not reached */ X} X Xchar * Xfh_pr(fh) Xnfs_fh *fh; X{ X char *p; X nfsstat status; X X p = fh_path(fh, &status); X if (status != NFS_OK) X return "///STALE///"; X else X return p; X} X Xint Xfh_create(fh, path) Xnfs_fh *fh; Xchar *path; X{ X svc_fh *key = (svc_fh *) fh; X fhcache *h; X int psi; X nfsstat status; X char *s; X X bzero((char *) fh, sizeof fh); X key->hash_path[0] = 0; X status = NFS_OK; X if ((psi = path_psi("/", &status, NULL)) == 0) X return (int) status; X s = path; X while ((s = index(s+1, '/')) != NULL) X { X if (++(key->hash_path[0]) >= HP_LEN) X return (int) NFSERR_NAMETOOLONG; X key->hash_path[key->hash_path[0]] = hash_psi(psi); X *s = '\0'; X if ((psi = path_psi(path, &status, NULL)) == 0) X return (int) status; X *s = '/'; X } X if (*(rindex(path, '/')+1) != '\0') X { X if (++(key->hash_path[0]) >= HP_LEN) X return (int) NFSERR_NAMETOOLONG; X key->hash_path[key->hash_path[0]] = hash_psi(psi); X if ((psi = path_psi(path, &status, NULL)) == 0) X return (int) status; X } X key->psi = psi; X h = fh_find(key, 1); X /* assert(h != NULL); */ X if (h->path == NULL) X { X h->fd = -1; X if ((h->path = malloc(strlen(path)+1)) == NULL) X mallocfailed(); X strcpy(h->path, path); X h->flags = 0; X } X return (int) status; X} X Xchar * Xfh_path(fh, status) Xnfs_fh *fh; Xnfsstat *status; X{ X fhcache *h; X X if ((h = fh_find((svc_fh *) fh, 0)) == NULL) X { X *status = NFSERR_STALE; X return NULL; X } X *status = NFS_OK; X return h->path; X} X Xstatic mutex io_state = idle; X Xint Xfh_fd(fh, status, omode) Xnfs_fh *fh; Xnfsstat *status; Xint omode; X{ X /* Currently we cache 1 open file descriptor. X * in the future we could allocate an array of size X * getdtablesize() which would contain psi's to provide X * an mapping from descriptor to psi's. X * Then we could maintain many concurrently open files. X */ X fhcache *h; X static int fd = -1; X static int psi = 0; X X if (fh == NULL && io_state == idle) X { X /* special case -- request to flush fd cache */ X if (fd >= 0) X close(fd); X fd = -1; X return -1; X } X X if ((h = fh_find((svc_fh *) fh, 0)) == NULL) X { X *status = NFSERR_STALE; X return -1; X } X io_state = active; X if (fd >= 0) X { X if (psi == h->h.psi && h->omode == omode) X return fd; X close(fd); X } X errno = 0; X h->fd = fd = open(h->path, omode); X h->omode = omode; X psi = h->h.psi; X *status = (nfsstat) errno; X return fd; X} X Xint Xfd_idle(fd) Xint fd; X{ X io_state = idle; X} X Xnfsstat Xfh_compose(dopa, new_fh, sbpp) Xdiropargs *dopa; Xnfs_fh *new_fh; Xstruct stat **sbpp; X{ X svc_fh *key; X fhcache *dirh, *h; X char *sindx; X int is_dd; X nfsstat ret; X struct stat sbuf; X char pathbuf[MAXPATHLEN+MAXNAMLEN+1]; X X if ((dirh = fh_find((svc_fh *) &(dopa->dir), 0)) == NULL) X return NFSERR_STALE; X X *new_fh = dopa->dir; X /* Construct path */ X X if (strcmp(dopa->name, ".") == 0) X { X *sbpp = NULL; X return NFS_OK; X } X if (strcmp(dopa->name, "..") == 0) X { X is_dd = 1; X sindx = rindex(dirh->path, '/'); X if (sindx == dirh->path) X strcpy(pathbuf, "/"); X else X { X int len = sindx - dirh->path; X strncpy(pathbuf, dirh->path, len); X pathbuf[len] = '\0'; X } X } X else X { X int len = strlen(dirh->path); X X is_dd = 0; X if (dirh->path[len-1] == '/') X len--; X strncpy(pathbuf, dirh->path, len); X pathbuf[len] = '/'; X strcpy(pathbuf + (len+1), dopa->name); X } X X key = (svc_fh *) new_fh; X if ((key->psi = path_psi(pathbuf, &ret, *sbpp)) == 0) X return ret; X X if (is_dd) X key->hash_path[key->hash_path[0]--] = 0; X else X { X if (++(key->hash_path[0]) >= HP_LEN) X return NFSERR_NAMETOOLONG; X key->hash_path[key->hash_path[0]] = hash_psi(dirh->h.psi); X } X h = fh_find(key, 1); X /* assert(h != NULL); */ X if (h->path == 0) X { X h->fd = -1; X if ((h->path = malloc(strlen(pathbuf)+1)) == NULL) X mallocfailed(); X strcpy(h->path, pathbuf); X h->flags = 0; X if (!is_dd X && access(dirh->path, R_OK) != 0 X && access(dirh->path, X_OK) == 0) X h->flags |= FHC_XONLY_PATH; X } X return NFS_OK; X} X Xint Xfh_psi(fh) Xnfs_fh *fh; X{ X svc_fh *h = (svc_fh *) fh; X return h->psi; X} X Xstatic int Xpath_psi(path, status, sbp) X char *path; X nfsstat *status; X struct stat *sbp; X{ X struct stat sbuf; X X if (sbp == NULL) X sbp = &sbuf; X if (lstat(path, sbp) < 0) X *status = (nfsstat) errno; X X if ((sbp->st_mode & S_IFMT) == S_IFDIR && strcmp(path, "/") != 0) X { X /* Special case for directories--test for mount point */ X struct stat ddbuf; X char *sindx; X char *name; X char squirrel; X X /* find start of last component of path */ X if ((sindx = rindex(path, '/')) == path) X { X sindx++; X name = sindx; X } X else X name = sindx + 1; X /* remove last element of path */ X squirrel = *sindx; X *sindx = '\0'; X if (lstat(path, &ddbuf) < 0) X { X *sindx = squirrel; X *status = (nfsstat) errno; X return 0; X } X /* sindx now points to directory entry name */ X if (ddbuf.st_dev != sbp->st_dev) X { X /* directory is a mount point */ X DIR *dirp; X struct direct *dp; X X errno = 0; X if ((dirp = opendir(path)) == NULL) X { X *sindx = squirrel; /* restore path */ X if (errno == EACCES) X goto unreadable; X if (errno != 0) X *status = (nfsstat) errno; X else X *status = NFSERR_NOENT; X } X else X { X *sindx = squirrel; /* restore path */ X *status = NFS_OK; X do X { X if ((dp = readdir(dirp)) == NULL) X { X *status = NFSERR_NOENT; X closedir(dirp); X return 0; X } X } while(strcmp(name, dp->d_name) != 0); X sbp->st_dev = ddbuf.st_dev; X sbp->st_ino = dp->d_ino; X closedir(dirp); X } X } X else X *sindx = squirrel; /* restore path */ X unreadable: X ; X } X return pseudo_inode(sbp->st_ino, sbp->st_dev); X} ________This_Is_The_END________ if test `wc -l < fh.c` -ne 825; then echo 'shar: fh.c was damaged during transit (should have been 825 bytes)' fi fi ; : end of overwriting check echo 'x - fh.h' if test -f fh.h; then echo 'shar: not overwriting fh.h'; else sed 's/^X//' << '________This_Is_The_END________' > fh.h X/* UNFSD - copyright Mark A Shand, May 1988. X * This software maybe be used for any purpose provided X * the above copyright notice is retained. It is supplied X * as is, with no warranty expressed or implied. X */ X X/* compatibility between mount and nfs_prot */ X#ifndef NFS_FHSIZE X#define NFS_FHSIZE FHSIZE X#endif X X#define HP_LEN (NFS_FHSIZE - sizeof(u_long)) X Xtypedef struct X{ X u_long psi; X u_char hash_path[HP_LEN]; X /* Hashed search path to this file. X * path is: hash_path[1] ... hash_path[hash_path[0]] X * X * hash_path[hash_path[0]+1] ... hash_path[HP_LEN-1] == 0 X */ X} X svc_fh; X Xextern void fh_init(); Xextern int fh_fd(); Xextern char *fh_path(); Xextern nfsstat fh_compose(); Xextern char *fh_pr(); Xextern int fh_psi(); ________This_Is_The_END________ if test `wc -l < fh.h` -ne 31; then echo 'shar: fh.h was damaged during transit (should have been 31 bytes)' fi fi ; : end of overwriting check echo 'x - init.c' if test -f init.c; then echo 'shar: not overwriting init.c'; else sed 's/^X//' << '________This_Is_The_END________' > init.c X/* UNFSD - copyright Mark A Shand, May 1988. X * This software maybe be used for any purpose provided X * the above copyright notice is retained. It is supplied X * as is, with no warranty expressed or implied. X */ X X/* X** Udp socket establishment routine X*/ X X X#ifndef lint Xstatic char sccsid[] = "@(#)makesock.c 1.0 88/03/12"; X#endif lint X X#include "unfsd.h" Xextern char *malloc(); Xextern char *realloc(); X X#define DEFAULT_EXPORTSFILE EXPORTSFILE X X#ifndef SYSERROR X#define SYSERROR (-1) X#endif X Xint Xmakesock(port,socksz) Xint port; Xint socksz; X{ X struct sockaddr_in my_sock; X int s; X extern int errno; X extern char *sys_errlist; X X bzero((char *)&my_sock, sizeof(my_sock)); X my_sock.sin_addr.s_addr = INADDR_ANY; X my_sock.sin_family = AF_INET; X my_sock.sin_port = htons(port); X X if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) X { X syslog(LOG_DAEMON|LOG_ERR, "could not make a socket: %s", X sys_errlist[errno]); X return SYSERROR; X } X#ifdef SO_SNDBUF X { X int sblen, rblen; X X sblen = rblen = socksz + 1024; X /* 1024 for rpc & transport overheads */ X if ( X setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 X || X setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof sblen) < 0 X ) X syslog(LOG_DAEMON|LOG_ERR, "setsockopt failed", X sys_errlist[errno]); X } X#endif X X if (bind(s, &my_sock, sizeof(my_sock)) == -1) X { X syslog(LOG_DAEMON|LOG_ERR, "could not bind name to socket", X sys_errlist[errno]); X return SYSERROR; X } X X return s; X} X Xftype ft_map[16]; Xint svc_euid; Xint svc_egid; Xint cur_gid; Xint svc_ngids; Xint svc_gids[NGROUPS+2]; X Xstatic clnt_param *clients = NULL; Xstatic clnt_param *default_client = NULL; X X#define LINE_SIZE 1024 X Xstatic char * Xparse_opts(s, terminator, o, client_name) Xchar *s; Xchar terminator; Xoptions *o; Xchar *client_name; X{ X /* parse option string pointed to by s and set o accordingly */ X char kwdbuf[LINE_SIZE]; X char *k; X X /* skip white */ X while (isspace(*s)) X s++; X while (*s != terminator) X { X k = kwdbuf; X while (isalnum(*s) || *s == '_') X *k++ = *s++; X *k = '\0'; X /* process keyword */ X if (strcmp(kwdbuf, "secure") == 0) X o->secure_port = 1; X else if (strcmp(kwdbuf, "insecure") == 0) X o->secure_port = 0; X else if (strcmp(kwdbuf, "root_squash") == 0) X o->root_squash = 1; X else if (strcmp(kwdbuf, "no_root_squash") == 0) X o->root_squash = 0; X else if (strcmp(kwdbuf, "ro") == 0) X o->read_only = 1; X else if (strcmp(kwdbuf, "rw") == 0) X o->read_only = 0; X else if (strcmp(kwdbuf, "link_relative") == 0) X o->link_relative = 1; X else if (strcmp(kwdbuf, "link_absolute") == 0) X o->link_relative = 0; X else if (strcmp(kwdbuf, "map_daemon") == 0) X o->uidmap = map_daemon; X else if (strcmp(kwdbuf, "map_identity") == 0) X o->uidmap = identity; X else X syslog(LOG_DAEMON|LOG_ERR, "Unknown keyword \"%s\"", kwdbuf); X while (isspace(*s)) X s++; X if (*s == ',') X s++; X else if (!isalnum(*s) && *s != '_' && *s != '\0') X { X if (client_name == NULL) X syslog(LOG_DAEMON|LOG_ERR, X "comma expected in option list for default client (found %c)", *s); X else X syslog(LOG_DAEMON|LOG_ERR, X "comma expected in option list for client %s (found %c)", X client_name, *s); X } X while (isspace(*s)) X s++; X if (*s == '\0' && *s != terminator) X { X syslog(LOG_DAEMON|LOG_ERR, X "missing terminator \"%c\" on option list", X terminator); X return s; X } X } X while (isspace(*s)) X s++; X return s; X} X Xstatic int Xfilt_getc(f) XFILE *f; X{ X int c; X X c = getc(f); X if (c == '\\') X { X c = getc(f); X if (c == '\n') X c = ' '; X else if (c != EOF) X ungetc(c, f); X c = '\\'; X } X else if (c == '#') X { X int lastc = c; X while ((c = getc(f)) != '\n' && c != EOF) X lastc = c; X if (c == '\n' && lastc == '\\') X c = getc(f); X } X return c; X} X X#define CHUNK_SIZE 512 X Xstatic int Xgetline(lbuf, f) Xchar **lbuf; XFILE *f; X{ X register c; X register char *p; X char *buf; X int sz = CHUNK_SIZE; X X if ((buf = malloc(CHUNK_SIZE)) == NULL) X mallocfailed(); X p = buf; X while ((c = filt_getc(f)) != '\n' && c != EOF) X { X if (p - buf == sz-2) X { X if ((buf = realloc(buf, sz*2)) == NULL) X mallocfailed(); X p = buf + sz-2; X sz *= 2; X } X *p++ = c; X } X if (c == EOF && p == buf) X { X free(buf); X *lbuf = NULL; X return 0; X } X *p++ = '\0'; X *lbuf = buf; X return 1; X} X Xunfsd_init(argc, argv) Xint argc; Xchar **argv; X{ X int i, n; X FILE *f; X char *lbuf; X char *p, *q, *r; X char *exportsfile = DEFAULT_EXPORTSFILE; X struct hostent *hent; X clnt_param *tmp; X char *mount_point; X X /* options */ X int promiscuous = 0; X char *o_string = NULL; X options def_opts; X X#ifndef DEBUG X { X int fd; X X if (fork()) X exit(0); X close(0); X close(1); X close(2); X if ((fd = open("/dev/tty", 2)) >= 0) X { X ioctl(fd, TIOCNOTTY, (char *)0); X (void) close(fd); X } X } X#endif DEBUG X /* setup defaults */ X def_opts.uidmap = identity; X def_opts.root_squash = 0; X def_opts.secure_port = 1; X def_opts.read_only = 1; X def_opts.link_relative = 1; X X openlog("unfsd", LOG_PID|LOG_TIME); X X argc--; argv++; X while (argc > 0) X { X if ((*argv)[0] == '-') X { X switch ((*argv)[1]) X { X case 'o': X if ((*argv)[2] == '\0' && argc > 1) X { X argc--; argv++; X o_string = *argv; X } X else X o_string = *argv + 2; X break; X case 'p': X promiscuous = 1; X break; X case 'f': X if ((*argv)[2] == '\0' && argc > 1) X { X argc--; argv++; X exportsfile = *argv; X } X else X exportsfile = *argv + 2; X break; X default: X syslog(LOG_DAEMON|LOG_ERR, "Unknown option"); X } X } X else X syslog(LOG_DAEMON|LOG_ERR, "Bad argument -- %s", *argv); X argc--; argv++; X } X X fh_init(); X X ft_map[0] = NFNON; X for (i = 1; i < 16; i++) X ft_map[i] = NFBAD; X#ifdef S_IFIFO X ft_map[ft_extr(S_IFIFO)] = NFFIFO; X#endif X ft_map[ft_extr(S_IFCHR)] = NFCHR; X ft_map[ft_extr(S_IFDIR)] = NFDIR; X ft_map[ft_extr(S_IFBLK)] = NFBLK; X ft_map[ft_extr(S_IFREG)] = NFREG; X ft_map[ft_extr(S_IFLNK)] = NFLNK; X ft_map[ft_extr(S_IFSOCK)] = NFSOCK; X X umask(0); X X svc_euid = geteuid(); X svc_ngids = getgroups(NGROUPS, svc_gids); X /* Does this always include gid and egid? I don't know. Play it safe */ X if (svc_ngids < 0) X svc_ngids = 0; X n = getgid(); X for (i = 0; i < svc_ngids; i++) X if (svc_gids[i] == n) X break; X if (i == svc_ngids) X svc_gids[svc_ngids++] = n; X n = svc_egid = getegid(); X for (i = 0; i < svc_ngids; i++) X if (svc_gids[i] == n) X break; X if (i == svc_ngids) X svc_gids[svc_ngids++] = n; X cur_gid = svc_gids[0]; X if (o_string != NULL) X parse_opts(o_string, '\0', &def_opts, NULL); X X if (exportsfile != NULL) X { X if ((f = fopen(exportsfile, "r")) == NULL) X { X syslog(LOG_DAEMON|LOG_WARNING, "Could not open %s: %m", exportsfile); X exit(1); X } X /* process exports file */ X while (getline(&lbuf, f)) X { X p = lbuf; X while (isspace(*p)) X p++; X q = p; X /* file-system name */ X while (*q != '\0' && !isspace(*q)) X q++; X if ((mount_point = malloc(q-p+1)) == NULL) X mallocfailed(); X for (r = mount_point; p < q;) X *r++ = *p++; X *r = '\0'; X p = q; X while (isspace(*p)) X p++; X while (*p != '\0') X { X q = p; X /* host name */ X while (*q != '\0' && !isspace(*q) && *q != '(') X q++; X if ((tmp = (clnt_param *) malloc(sizeof *tmp)) == NULL X || (tmp->clnt_name = malloc(q-p+1)) == NULL) X mallocfailed(); X for (r = tmp->clnt_name; p < q;) X *r++ = *p++; X *r = '\0'; X tmp->mount_point = mount_point; X if ((hent = gethostbyname(tmp->clnt_name)) == NULL) X { X syslog(LOG_DAEMON|LOG_WARNING, "Unknown host %s in %s", X tmp->clnt_name, exportsfile); X free(tmp->clnt_name); free(tmp); X continue; X } X tmp->clnt_addr = *((struct in_addr *)hent->h_addr); X tmp->next = clients; X clients = tmp; X tmp->o = def_opts; X while (isspace(*p)) X p++; X if (*p == '(') X p = parse_opts(p+1, ')', &(tmp->o), tmp->clnt_name); X } X free(lbuf); X } X fclose(f); X } X if (promiscuous) X { X if ((tmp = (clnt_param *) malloc(sizeof *tmp)) == NULL) X mallocfailed(); X tmp->clnt_name = NULL; X tmp->mount_point = NULL; X default_client = tmp; X tmp->o = def_opts; X } X} X Xint X_in_gid_set(gid) Xint gid; X{ X int i; X X for (i = 0; i < svc_ngids; i++) X if (svc_gids[i] == gid) X { X cur_gid = gid; X return 1; X } X return 0; X} X Xclnt_param * Xknownclient(rqstp) X struct svc_req *rqstp; X{ X clnt_param **cpp, *cp; X X /* find host parameter struct */ X for (cpp = &clients; *cpp != NULL; cpp = &((*cpp)->next)) X { X if ((*cpp)->clnt_addr.s_addr == svc_getcaller(rqstp->rq_xprt)->sin_addr.s_addr) X { X cp = *cpp; X if (cp != clients) X { X /* Move to front */ X *cpp = cp->next; X cp->next = clients; X clients = cp; X } X goto found_it; X } X } X if (default_client != NULL) X cp = default_client; X else X { X syslog(LOG_DAEMON|LOG_CRIT, "Access attempt by unknown client %08X", X ntohl(svc_getcaller(rqstp->rq_xprt)->sin_addr)); X return NULL; X } X found_it: X /* check request originated on a privileged port */ X if (ntohs(svc_getcaller(rqstp->rq_xprt)->sin_port) >= IPPORT_RESERVED && cp->o.secure_port) X { X syslog(LOG_DAEMON|LOG_CRIT, "NFS request from %08X originated on insecure port", X ntohl(svc_getcaller(rqstp->rq_xprt)->sin_addr)); X return NULL; X } X return cp; X} ________This_Is_The_END________ if test `wc -l < init.c` -ne 462; then echo 'shar: init.c was damaged during transit (should have been 462 bytes)' fi fi ; : end of overwriting check echo 'x - mount.x' if test -f mount.x; then echo 'shar: not overwriting mount.x'; else sed 's/^X//' << '________This_Is_The_END________' > mount.x X/* @(#)mount.x 1.2 87/11/12 3.9 RPCSRC */ X/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ X X/* X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for X * unrestricted use provided that this legend is included on all tape X * media and as a part of the software program in whole or part. Users X * may copy or modify Sun RPC without charge, but are not authorized X * to license or distribute it to anyone else except as part of a product or X * program developed by the user. X * X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. X * X * Sun RPC is provided with no support and without any obligation on the X * part of Sun Microsystems, Inc. to assist in its use, correction, X * modification or enhancement. X * X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC X * OR ANY PART THEREOF. X * X * In no event will Sun Microsystems, Inc. be liable for any lost revenue X * or profits or other special, indirect and consequential damages, even if X * Sun has been advised of the possibility of such damages. X * X * Sun Microsystems, Inc. X * 2550 Garcia Avenue X * Mountain View, California 94043 X */ X X/* X * Protocol description for the mount program X */ X X Xconst MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ Xconst MNTNAMLEN = 255; /* maximum bytes in a name argument */ Xconst FHSIZE = 32; /* size in bytes of a file handle */ X X/* X * The fhandle is the file handle that the server passes to the client. X * All file operations are done using the file handles to refer to a file X * or a directory. The file handle can contain whatever information the X * server needs to distinguish an individual file. X */ Xstruct fhandle { X opaque data[FHSIZE]; X}; X X/* X * If a status of zero is returned, the call completed successfully, and X * a file handle for the directory follows. A non-zero status indicates X * some sort of error. The status corresponds with UNIX error numbers. X */ Xunion fhstatus switch (unsigned fhs_status) { Xcase 0: X struct fhandle fhs_fhandle; Xdefault: X void; X}; X X/* X * The type dirpath is the pathname of a directory X */ Xtypedef string dirpath<MNTPATHLEN>; X X/* X * The type name is used for arbitrary names (hostnames, groupnames) X */ Xtypedef string name<MNTNAMLEN>; X X/* X * A list of who has what mounted X */ Xstruct mountlist { X name ml_hostname; X dirpath ml_directory; X mountlist *ml_next; X}; X X/* X * A list of netgroups X */ Xtypedef struct groupnode *groups; Xstruct groupnode { X name gr_name; X groups *gr_next; X}; X X/* X * A list of what is exported and to whom X */ Xstruct exports { X dirpath ex_dir; X groups ex_groups; X exports *ex_next; X}; X Xprogram MOUNTPROG { X /* X * Version one of the mount protocol communicates with version two X * of the NFS protocol. The only connecting point is the fhandle X * structure, which is the same for both protocols. X */ X version MOUNTVERS { X /* X * Does no work. It is made available in all RPC services X * to allow server reponse testing and timing X */ X void X MOUNTPROC_NULL(void) = 0; X X /* X * If fhs_status is 0, then fhs_fhandle contains the X * file handle for the directory. This file handle may X * be used in the NFS protocol. This procedure also adds X * a new entry to the mount list for this client mounting X * the directory. X * Unix authentication required. X */ X fhstatus X MOUNTPROC_MNT(dirpath) = 1; X X /* X * Returns the list of remotely mounted filesystems. The X * mountlist contains one entry for each hostname and X * directory pair. X */ X mountlist X MOUNTPROC_DUMP(void) = 2; X X /* X * Removes the mount list entry for the directory X * Unix authentication required. X */ X void X MOUNTPROC_UMNT(dirpath) = 3; X X /* X * Removes all of the mount list entries for this client X * Unix authentication required. X */ X void X MOUNTPROC_UMNTALL(void) = 4; X X /* X * Returns a list of all the exported filesystems, and which X * machines are allowed to import it. X */ X exports X MOUNTPROC_EXPORT(void) = 5; X X /* X * Identical to MOUNTPROC_EXPORT above X */ X exports X MOUNTPROC_EXPORTALL(void) = 6; X } = 1; X} = 100005; ________This_Is_The_END________ if test `wc -l < mount.x` -ne 161; then echo 'shar: mount.x was damaged during transit (should have been 161 bytes)' fi fi ; : end of overwriting check exit 0