Subject: RFS: remote file system (part 3 of 7) Newsgroups: mod.sources Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 79 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 3 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/list.c # remote/make.base # remote/make.base.M68 # remote/make.base.magnolia # remote/make.base.pyramid # remote/make.base.vax # remote/make.base.vaxnorfs # remote/new.c # remote/newinit.c # remote/rhost.c # remote/rmtmnt.c # remote/route.c # remote/server.h # remote/serverdata.c # remote/serverdir.c # # remote/list.c # if [ -f remote/list.c ]; then echo -n 'Hit to overwrite remote/list.c or ^C to quit' read ans rm -f remote/list.c fi sed -e 's/^.//' << \SHAREOF > remote/list.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: list.c,v $ X * Revision 2.0 85/12/07 18:21:44 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: list.c,v 2.0 85/12/07 18:21:44 toddb Rel $"; X#include "server.h" X#include X X/* X * Stick a new item of any type on top of the list. X */ Xl_list *addlist(list, item) X register l_list **list; X register l_list *item; X{ X item->l_next = *list; X if (*list) X { X item->l_prev = (*list)->l_prev; X (*list)->l_prev = item; X } X else X item->l_prev = item; X *list = item; X return(item); X} X X/* X * delete an item from a list. The item itself is left intact. It is X * the responsibility of the caller to deal with the deleted item. X */ Xl_list *deletelist(list, item) X register l_list **list; X register l_list *item; X{ X if (item == *list) X { X if (item->l_next == NULL) X *list = NULL; X else X { X *list = item->l_next; X item->l_next->l_prev = item->l_next; X } X } X else X { X item->l_prev->l_next = item->l_next; X if (item->l_next != NULL) X item->l_next->l_prev = item->l_prev; X } X return (*list); X} X X/* X * stick 'item' at the top of the 'list' ( if it isn't there X * already. X */ Xl_list *toplist(list, item) X register l_list **list; X register l_list *item; X{ X if (item == *list) X return; X item->l_prev->l_next = item->l_next; X if (item->l_next) X item->l_next->l_prev = item->l_prev; X item->l_next = (*list); X /* X * if our target is the last on the list, then X * be careful that we don't make a cycle. Since X * we want the head of the list's l_prev pointer X * to point to the last in the list, we don't X * have to do anything. X */ X if (item != (*list)->l_prev) /* NOT last on list */ X item->l_prev = (*list)->l_prev; X (*list)->l_prev = item; X *list = item; X} SHAREOF chmod 444 remote/list.c # # remote/make.base # if [ -f remote/make.base ]; then echo -n 'Hit to overwrite remote/make.base or ^C to quit' read ans rm -f remote/make.base fi sed -e 's/^.//' << \SHAREOF > remote/make.base XSOBJS = change.$O file.$O fileserver.$O find.$O \ X info.$O init.$O list.$O new.$O \ X rhost.$O route.$O serverdata.$O serverdir.$O serverio.$O \ X serversyscall.$O XCFILES = change.c file.c fileserver.c find.c \ X info.c init.c list.c new.c \ X rhost.c route.c serverdata.c serverdir.c serverio.c \ X serversyscall.c X Xall: $(ALL) X X$(RFS_SERVER): $(SOBJS) X $(CC) -o $@ $(SOBJS) $(LDFLAGS) X $(XINU) $(RFS_SERVER) X$(RMTMNT): rmtmnt.$O X $(CC) -o $@ rmtmnt.$O $(LDFLAGS) X $(XINU) $(RMTMNT) X$(DEBUG): debug.$O X $(CC) -o $@ debug.$O $(LDFLAGS) X $(XINU) $(DEBUG) Xtags: $(CFILES) X ctags $(CFILES) $(INCLUDE) X$(SOBJS): $(INCLUDE) X Xinstall: all X $(INSTALL) -c -m 755 $(RFS_SERVER) $(DEST)/etc/rfs_server X $(INSTALL_RMTMNT) -c -m 0755 $(RMTMNT) $(DEST)/etc/rmtmnt SHAREOF chmod 664 remote/make.base # # remote/make.base.M68 # if [ -f remote/make.base.M68 ]; then echo -n 'Hit to overwrite remote/make.base.M68 or ^C to quit' read ans rm -f remote/make.base.M68 fi sed -e 's/^.//' << \SHAREOF > remote/make.base.M68 XDEST = /usr3/mag XHOST = XINCLUDE = $(DEST)/usr/include/remote/remotefs.h server.h XCFLAGS = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -DMACHTYPE=magnolia XLDFLAGS = -z XCC = cc68 XO = b XRFS_SERVER = rfs_server.x XRMTMNT = rmtmnt.x XDEBUG = debug.x XINSTALL_RMTMNT = install68 XINSTALL = install68 XALL = $(RFS_SERVER) $(RMTMNT) XXINU = xinu68 X X.SUFFIXES: X.SUFFIXES: .b .c X X.c.b: X $(CC) $(CFLAGS) $< -c SHAREOF chmod 664 remote/make.base.M68 # # remote/make.base.magnolia # if [ -f remote/make.base.magnolia ]; then echo -n 'Hit to overwrite remote/make.base.magnolia or ^C to quit' read ans rm -f remote/make.base.magnolia fi sed -e 's/^.//' << \SHAREOF > remote/make.base.magnolia XHOST = tekcrl XINCLUDE = /usr/include/remote/remotefs.h server.h XO = o XCFLAGS = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS XLDFLAGS = -z XRFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL = install68 XINSTALL_RMTMNT = install68 XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : SHAREOF chmod 664 remote/make.base.magnolia # # remote/make.base.pyramid # if [ -f remote/make.base.pyramid ]; then echo -n 'Hit to overwrite remote/make.base.pyramid or ^C to quit' read ans rm -f remote/make.base.pyramid fi sed -e 's/^.//' << \SHAREOF > remote/make.base.pyramid XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = install XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : XDEFINES = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -I/usr/include/sys XCFLAGS = -O ${DEFINES} -I../usr.include SHAREOF chmod 644 remote/make.base.pyramid # # remote/make.base.vax # if [ -f remote/make.base.vax ]; then echo -n 'Hit to overwrite remote/make.base.vax or ^C to quit' read ans rm -f remote/make.base.vax fi sed -e 's/^.//' << \SHAREOF > remote/make.base.vax XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = install XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : XDEFINES = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=0,1,2,3 -DREMOTEFS XCFLAGS = -O ${DEFINES} -I../usr.include SHAREOF chmod 664 remote/make.base.vax # # remote/make.base.vaxnorfs # if [ -f remote/make.base.vaxnorfs ]; then echo -n 'Hit to overwrite remote/make.base.vaxnorfs or ^C to quit' read ans rm -f remote/make.base.vaxnorfs fi sed -e 's/^.//' << \SHAREOF > remote/make.base.vaxnorfs XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = : XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) XXINU = : XCFLAGS = -O -DRFSDEBUG -DBYTEORDER=0,1,2,3 -DNREMOTE=1 -I../usr.include SHAREOF chmod 664 remote/make.base.vaxnorfs # # remote/new.c # if [ -f remote/new.c ]; then echo -n 'Hit to overwrite remote/new.c or ^C to quit' read ans rm -f remote/new.c fi sed -e 's/^.//' << \SHAREOF > remote/new.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: new.c,v $ X * Revision 2.0 85/12/07 18:21:48 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: new.c,v 2.0 85/12/07 18:21:48 toddb Rel $"; X#include "server.h" X#include X Xextern short current_pid; Xextern hosts *host; X Xusers *newuser() X{ X register users *user; X X user = (users *)malloc(sizeof(users)); X if (user == NULL) X log_fatal("cannot allocate space\n"); X bzero(user, sizeof(users)); X return(user); X} X Xhosts *newhost() X{ X register hosts *h; X X h = (hosts *)malloc(sizeof(hosts)); X if (h == NULL) X log_fatal("cannot allocate space\n"); X bzero(h, sizeof(hosts)); X h->h_cmdfd = -1; X return(h); X} X Xrusers *newruser() X{ X register rusers *ruser; X X ruser = (rusers *)malloc(sizeof(rusers)); X if (ruser == NULL) X log_fatal("cannot allocate space\n"); X bzero(ruser, sizeof(rusers)); X return(ruser); X} X Xprocess *newprocess() X{ X register process *p; X X p = (process *)malloc(sizeof(process)); X if (p == NULL) X log_fatal("cannot allocate space\n"); X bzero(p, sizeof(process)); X return(p); X} X Xfreeproc(p) X register process *p; X{ X if (p->p_execfd >= 0) X close(p->p_execfd); X free(p); X} X Xchar **newname(namelist, name) X register char **namelist; X register char *name; X{ X register long i = 0; X X if (namelist == NULL) X namelist = (char **)malloc(sizeof(char *) * 2); X else X { X /* X * count the elements in the list now. X */ X for (i=0; namelist && namelist[i]; i++) ; X X namelist = (char **)realloc(namelist, sizeof(char *) * (i+2)); X } X namelist[ i++ ] = copy(name); X namelist[ i ] = NULL; X return(namelist); X} X X/* X * Add a group to 'user' unless he has exceeded the limit or the group X * is already in his domain. X */ Xaddgroup(user, gid) X register users *user; X register short gid; X{ X register long i = 0, X *gr = user->u_local_groups; X X for (i=0; i < user->u_numgroups; i++) X if (gr[ i ] == gid) X return; X if (i >= NGROUPS) X return; X gr[ user->u_numgroups++ ] = gid; X} X Xprocess *add_new_process(uid, pid) X register short uid, pid; X{ X register process *p; X register long i; X X debug0("allocate new proc: pid=%d uid=%d host=%s\n", X pid, uid, host->h_names[0]); X setup_proc(p = newprocess(), uid, pid); X addlist(&host->h_proclist, p); X X /* X * Initialize the file descriptors for this process. X */ X for(i=0; ip_fds[ i ] = 0x80; /* -128 */ X X return(p); X} X Xsetup_proc(proc, uid, pid) X register process *proc; X register short uid, pid; X{ X register rusers *ruser; X X proc->p_pid = pid; X proc->p_uid = uid; X proc->p_handler = current_pid; X proc->p_returnval = 0; X proc->p_execfd = -1; X if (ruser = findremuid(&host->h_rusers, uid)) X proc->p_ruser = ruser; X else X proc->p_ruser = host->h_default_ruser; X} SHAREOF chmod 444 remote/new.c # # remote/newinit.c # if [ -f remote/newinit.c ]; then echo -n 'Hit to overwrite remote/newinit.c or ^C to quit' read ans rm -f remote/newinit.c fi sed -e 's/^.//' << \SHAREOF > remote/newinit.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: init.c,v $ X * Revision 2.0 85/12/07 18:21:37 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: init.c,v 2.0 85/12/07 18:21:37 toddb Rel $"; X#include "server.h" X#include X#include X#include X#include X#include X#include X#include X#include X#include X Xextern hosts *hostlist; Xextern hosts *thishost; Xextern users *userlist; Xextern users *default_user; Xextern char hostname[]; Xextern char *service; Xextern short current_uid; Xextern short current_pid; Xextern process *wildcard; Xextern struct sigvec sig_vec; Xextern struct sigvec sig_name; Xextern struct sigvec sig_alarm; Xextern struct sigvec sig_ignore; Xextern struct sigvec sig_continue; X#ifdef RFSDEBUG Xextern struct sigvec sig_debug; X#endif Xextern struct stat root; X X/* X * Initialize the host tables and user tables. X */ Xinit() X{ X long tt; X struct hostent *gethostent(); X struct passwd *getpwent(); X struct group *getgrent(); X X /* X * catch signals. X */ X sigvec(SIGHUP, &sig_ignore, (struct sigvec *)0); X sigvec(SIGINT, &sig_vec, (struct sigvec *)0); X sigvec(SIGQUIT, &sig_vec, (struct sigvec *)0); X sigvec(SIGILL, &sig_vec, (struct sigvec *)0); X#ifdef RFSDEBUG X sigvec(SIGTRAP, &sig_debug, (struct sigvec *)0); X#endif RFSDEBUG X /* SIGIOT */ X /* SIGEMT */ X /* SIGFPE */ X /* SIGKILL */ X sigvec(SIGBUS, &sig_vec, (struct sigvec *)0); X sigvec(SIGSEGV, &sig_vec, (struct sigvec *)0); X sigvec(SIGSYS, &sig_vec, (struct sigvec *)0); X sigvec(SIGPIPE, &sig_vec, (struct sigvec *)0); X sigvec(SIGALRM, &sig_alarm, (struct sigvec *)0); X sigvec(SIGTERM, &sig_vec, (struct sigvec *)0); X sigvec(SIGURG, &sig_name, (struct sigvec *)0); X /* SIGSTOP */ X /* SIGTSTP */ X /* SIGCONT */ X /* SIGCHLD */ X sigvec(SIGTTIN, &sig_vec, (struct sigvec *)0); X sigvec(SIGTTOU, &sig_vec, (struct sigvec *)0); X sigvec(SIGIO, &sig_continue, (struct sigvec *)0); X sigvec(SIGXCPU, &sig_vec, (struct sigvec *)0); X sigvec(SIGXFSZ, &sig_vec, (struct sigvec *)0); X sigvec(SIGVTALRM, &sig_vec, (struct sigvec *)0); X /* SIGPROF */ X X /* X * set up some important global values, including uid, pid, X * the pipe file descriptors for messages to and from the gateway X * server. Register as the nameserver. Get host name. Get service. X * Get root stat info. X */ X if (chdir("/") == -1) X log_fatal("cannot chdir(\"/\")\n"); X wildcard = newprocess(); X fcntl(2, F_SETFL, FAPPEND); X close(0); X close(1); X change_to_uid(0); X if (gethostname(hostname, HOSTNAMELEN) < 0 || *hostname == '\0') X log_fatal("host name not set!\n"); X if (stat("/", &root) < 0) X log_fatal("cannot stat /\n"); X#ifdef CANREMOTE X if (remotename(NM_SERVER, 0, 0, 0) < 0) X log("cannot register as nameserver\n"); X /* X * Turn off remote access, if we have any. X */ X remoteoff(NULL); X#endif X tt = open("/dev/tty", 2); X X if (tt >= 0) X { X ioctl(tt, TIOCNOTTY, 0); X close(tt); X } X setpgrp(0,0); X X initusers(); X initgroups(); X inithosts(); X initrhosts(); X} X X/* X * build the list of users on this host (where the server runs). X */ Xinitusers() X{ X register struct passwd *pw; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X while(pw = getpwent()) X { X if (*pw->pw_dir == '\0' || *pw->pw_name == '\0') X { X log("login \"%s\" has problems, dir=\"%s\"\n", X pw->pw_name, pw->pw_dir); X continue; X } X user = newuser(); X user->u_local_uid = pw->pw_uid; X user->u_name = copy( pw->pw_name ); X addgroup(user, pw->pw_gid); X user->u_dir = copy( pw->pw_dir ); X sprintf(pbuf, "%s/.rhosts", pw->pw_dir); X user->u_rhosts = copy( pbuf ); X addlist(&userlist, user); X } X endpwent(); X if (user = findusername(DEFAULTUSER)) X default_user = user; X else X log_fatal("The user \"%s\" must be in /etc/passwd (%s)\n", X DEFAULTUSER, "for default permissions"); X} X X/* X * Build the list of groups that each user belongs to. X */ Xinitgroups() X{ X register struct group *gr; X register users *user; X register char **p; X X X while(gr = getgrent()) X { X for (p = gr->gr_mem; *p; p++) X if (user = findusername(*p)) X addgroup(user, gr->gr_gid); X else X log("group %s: bad user=%s\n", X gr->gr_name, *p); X } X endgrent(); X} X X/* X * Then build the list of all hosts. X */ Xinithosts() X{ X register struct hostent *h; X register rusers *ruser; X register hosts *hst; X register users *user; X register long i; X boolean duplicate; X X while (h = gethostent()) X { X /* X * One physical host may have more than one physical X * address each having a unique host name associated X * with it. If we find any entry having one of its aliases X * match a previous alias, then simply fold all aliases X * into it, and continue. X */ X duplicate = FALSE; X for (i = -1; i < 0 || h->h_aliases[ i ]; i++) X { X if (i < 0) X hst = findhost(h->h_name); X else X hst = findhost(h->h_aliases[i]); X if (hst) X { X duplicate = TRUE; X break; X } X } X X /* X * If we have a redundant host... add all the names X * in; newname will remove redundant copies. X */ X if (!duplicate) X hst = newhost(); X hst->h_names = newname(hst->h_names, h->h_name); X for (i=0; h->h_aliases[ i ]; i++) X hst->h_names = newname(hst->h_names, X h->h_aliases[ i ]); X if (duplicate) X X hst->h_addr = *((struct in_addr *)(h->h_addr)); X addlist(&hostlist, hst); X X /* X * now if there exists a user on this machine having X * the same name as the name of this host (NOT AN X * ALIAS!), then that will be our defaut local user X * to map to. Be sure that we don't allow a machine X * to be mapped onto a user if the uid is real small: X * e.g. a machine named root, where all its user ids X * become root using the remote fs! X */ X user = findusername(hst->h_names[ 0 ]); X if (user && user->u_local_uid <= UID_TOO_LOW) X { X log("host/user %s: uid %d too low for alias\n", X hst->h_names[ 0 ], user->u_local_uid); X user = NULL; X } X else if (user) X { X hst->h_default_user = user; X debug2("default user for host %s (%s) is %s\n", X hst->h_names[ 0 ], X inet_ntoa(hst->h_addr), user->u_name); X } X ruser = hst->h_default_ruser = newruser(); X if (user) X ruser->r_user = user; X else X ruser->r_user = default_user; X ruser->r_uid = -1; X ruser->r_name = copy(BOGUSUSER); X } X endhostent(); X if ((thishost = findhostname(hostname)) == NULL) X log_fatal("this host (\"%s\") is not in host file\n", X hostname); X} X X/* X * Now for each user that has a .rhosts file, assemble the X * references and attach them to the appropriate host. X */ Xinitrhosts() X{ X register hosts *hst; X register rhost *rh; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X for (user=userlist; user; user=user->u_next) X { X setrhost(user->u_rhosts); X while (rh = getrhostent(pbuf)) X if (hst = findhostname(rh->rh_host)) X addremoteuser(hst, user, rh->rh_user); X endrhost(); X } X} X Xchar *copy(string) X register char *string; X{ X register char *ret = malloc( strlen(string)+1 ); X X if (ret == NULL) X log_fatal("cannot allocate space\n"); X strcpy(ret, string); X return(ret); X} X X/* X * Add a remote user to those recognized on a certain host. X */ Xaddremoteuser(h, user, remoteuser) X register hosts *h; X register users *user; X register char *remoteuser; X{ X register rusers *ruser; X register long old = FALSE; X X debug2("\t%s!%s --> %s ", *h->h_names, remoteuser, user->u_name); X if ((ruser = findrusername(&h->h_rusers, remoteuser)) == NULL) X { X debug2("\n"); X ruser = newruser(); X } X else X { X old = TRUE; X if (strcmp(remoteuser, user->u_name) != 0) X { X debug2("(old, ignored)\n"); X return; X } X else X debug2("(old)\n"); X } X ruser->r_name = copy(remoteuser); X ruser->r_uid = -1; X ruser->r_user = user; X if (! old) X addlist(&h->h_rusers, ruser); X} SHAREOF chmod 664 remote/newinit.c # # remote/rhost.c # if [ -f remote/rhost.c ]; then echo -n 'Hit to overwrite remote/rhost.c or ^C to quit' read ans rm -f remote/rhost.c fi sed -e 's/^.//' << \SHAREOF > remote/rhost.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: rhost.c,v $ X * Revision 2.0 85/12/07 18:21:52 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: rhost.c,v 2.0 85/12/07 18:21:52 toddb Rel $"; X#include X#include "server.h" X Xstatic char *rhostpath; Xstatic FILE *fd; Xstatic rhost rh; X Xsetrhost(path) X register char *path; X{ X extern int errno; X X if ((fd = fopen(path, "r")) != 0) X debug2("rhost %s\n", path); X errno = 0; X} X Xrhost *getrhostent(buf) X register char *buf; X{ X register char *p; X X while (1) X { X if (fd == NULL || fgets(buf, BUFSIZ, fd) == NULL) X return(NULL); X X /* X * assign the first token to rh_host and then look for the X * second token on the line. If there is none, then X * don't return this entry because we can never map X * a remote user id name of "" to anything meaningful. X */ X rh.rh_host = buf; X for (p=buf; *p && *p != ' ' && *p != '\n'; p++) ; X if (*p == '\n' || *p == '\0') X continue; X X /* X * remove the newline on the end X */ X rh.rh_user = p+1; X *p = '\0'; X for (p++; *p && *p != ' ' && *p != '\n'; p++) ; X *p = '\0'; X break; X } X return(&rh); X} X Xendrhost() X{ X if (fd) X { X fclose(fd); X fd = NULL; X } X} SHAREOF chmod 444 remote/rhost.c # # remote/rmtmnt.c # if [ -f remote/rmtmnt.c ]; then echo -n 'Hit to overwrite remote/rmtmnt.c or ^C to quit' read ans rm -f remote/rmtmnt.c fi sed -e 's/^.//' << \SHAREOF > remote/rmtmnt.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: rmtmnt.c,v $ X * Revision 2.0 85/12/07 18:21:56 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: rmtmnt.c,v 2.0 85/12/07 18:21:56 toddb Rel $"; X#include "server.h" X#include X#include X#include X#include X#include X#include X Xextern int errno; /* for errors */ Xchar *service; /* service name */ Xchar byteorder[4] = { BYTEORDER }; X X/* X * for slow or dead remote hosts, we catch alarms. X */ Xint onalrm(); Xstruct sigvec vec = { onalrm, 0, 0 }; X X/* X * Displaying current mount points requires that we read kernel space. X */ Xstruct nlist nl[] = { X#ifdef magnolia X { "remote_info" }, X#else X { "_remote_info" }, X#endif X { "" }, X}; X#ifdef magnolia Xchar *kernel = "/magix"; X#else Xchar *kernel = "/vmunix"; X#endif X Xmain(argc, argv) X int argc; X char **argv; X{ X long generic = FALSE, X unmount = FALSE; X char *mntpt = NULL, X *host = NULL; X X /* X * Parse the args. X */ X for (argv++, argc--; argc; argv++, argc--) X { X if (**argv != '-') X break; X switch(argv[0][1]) { X case 's': /* service name */ X if (argv[0][2]) X service = argv[0]+2; X else X argv++, argc--, service = argv[0]; X break; X case 'g': /* Make this a generic mount point */ X generic = TRUE; X break; X case 'u': /* unmount this mount point */ X unmount = TRUE; X break; X default: X fprintf(stderr, "unknown option = %s\n", *argv); X usage(); X exit(1); X } X } X X if (! generic && ! unmount && argc-- > 0) X host = *argv++; X if (argc-- > 0) X { X mntpt = *argv++; X if (*mntpt != '/') X { X fprintf(stderr, "mount point must begin with '/'\n"); X mntpt = NULL; X } X } X else X { X show(); X exit(0); X } X X if (argc > 0 X || (generic && unmount) X || (mntpt == NULL)) X usage(); X X if (unmount) X turnoff(mntpt); X else X turnon(mntpt, host); X} X X/* X * Display the current mount points in the kernal. X */ Xshow() X{ X long index = 0, X diff, X now, X kfd; X char buf[BUFSIZ], X *p; X struct sockaddr_in hostaddr; X struct sockaddr_in *sys; X struct servent *servp; X struct hostent *hostent; X struct remoteinfo rinfo[ R_MAXSYS ], X *rp; X struct mbuf bufs[ R_MAXSYS ], X *m; X X servp = getservbyname(REMOTE_FS_SERVER, "tcp"); X /* X * Get the address of the remote mount point information X * and read kernel memory. X */ X nlist(kernel, nl); X if(nl[0].n_type == 0) X log_fatal("no %s for namelist\n", kernel); X kfd = open("/dev/kmem", 0); X if(kfd < 0) X log_fatal("cannot open /dev/kmem\n"); X lseek(kfd, (long)nl[0].n_value, 0); X read(kfd, rinfo, sizeof(struct remoteinfo) * R_MAXSYS); X X /* X * Now get the mbufs on each mount point. X */ X m = bufs; X time(&now); X for (index=0, rp = rinfo; rp < rinfo+R_MAXSYS; rp++, index++) X { X buf[0] = '\0'; X if (rp->r_name || rp->r_mntpt) X printf("%d: ", index); X else X continue; X if (rp->r_name) X { X lseek(kfd, (long)rp->r_name, 0); X read(kfd, m, sizeof(struct mbuf)); X rp->r_name = m++; X sys = mtod(rp->r_name, struct sockaddr_in *); X hostent = gethostbyaddr(&sys->sin_addr, X sizeof (struct in_addr), sys->sin_family); X if (hostent == NULL) X { X log("no host entry for %s\n", X inet_ntoa(sys->sin_addr)); X continue; X } X bprintf(buf, "%s(%s) on ", X hostent->h_name, inet_ntoa(sys->sin_addr)); X } X else X bprintf(buf, "generic mount point "); X bprintf(buf, "%s", rp->r_mntpath); X if (rp->r_mntpt == NULL) X bprintf(buf, ", implied"); X if (rp->r_name && sys->sin_port != servp->s_port) X bprintf(buf, ", port %d", sys->sin_port); X if (rp->r_sock) X bprintf(buf, ", connected"); X if (rp->r_close) X bprintf(buf, ", closing"); X if (rp->r_users) X bprintf(buf, ", %d process%s", X rp->r_users, rp->r_users > 1 ? "es" : ""); X if (rp->r_nfile) X bprintf(buf, ", %d open file%s", X rp->r_nfile, rp->r_nfile > 1 ? "s" : ""); X if (rp->r_nchdir) X bprintf(buf, ", %d chdir%s", X rp->r_nchdir, rp->r_nchdir > 1 ? "'s" : ""); X if (rp->r_opening) X bprintf(buf, ", opening"); X if (rp->r_failed) X { X bprintf(buf, ", connect failed, retry "); X diff = rp->r_age - now; X if (diff <= 0) X bprintf(buf, "time reached"); X else X { X bprintf(buf, "in "); X if (diff / 60) X bprintf(buf, "%d minute%s", diff/60, X (diff/60) > 1 ? "s" : ""); X if (diff / 60 && diff % 60) X bprintf(buf, " and "); X if (diff % 60) X bprintf(buf, "%d second%s", diff%60, X (diff%60) > 1 ? "s" : ""); X } X } X else if(rp->r_sock == NULL && rp->r_age) X { X bprintf(buf, ", last closed %s", X ctime(&rp->r_age)); X buf[ strlen(buf)-1 ] = '\0'; /* remove newline */ X } X printf("%s\n", buf); X } X} X X/* X * buffer printf. i.e. do a printf into a buffer, appending to whatever X * is there. Split long lines. X */ Xbprintf(buf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X char *buf; X{ X char xbuf[ BUFSIZ ], X *pfrom, *pto, c; X long col; X X sprintf(xbuf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X for (pto = buf; *pto; pto++) ; X for (pfrom = xbuf, col=0; *pfrom; pfrom++, col++) X { X c = *pfrom; X *pto++ = c; X if (c == '\n') X col = -1; X else if (c == ' ' && col > 50) X { X *pto++ = '\n'; X *pto++ = '\t'; X col = 7; X } X } X *pto = '\0'; X} X X/* X * Do a mount. X */ Xturnon(mntpt, host) X char *mntpt, *host; X{ X int index, ret, fdout, fdin; X struct message msgbuf, *msg = &msgbuf; X struct sockaddr_in sys; X char buf[ BUFSIZ ]; X X if (strlen(mntpt) >= R_MNTPATHLEN) X log_fatal("mount point must be < %d chars\n", R_MNTPATHLEN); X X /* X * Connect to the machine and send it our byte order and X * password file. X */ X if (host) X { X if ((fdout = tcpname(&sys, host)) < 0) X log("system unreachable now..."); X index = remoteon(mntpt, strlen(mntpt)+1, X &sys, sizeof(struct sockaddr_in)); X } X else X index = remoteon(mntpt, strlen(mntpt), 0, 0); X if (index == -1) X log_fatal("cant mount remote fs\n"); X else if (host && fdout < 0) X log(" system mounted anyway\n"); X if (host == NULL) X return; X if ((fdin = open("/etc/passwd", O_RDONLY)) == -1) X log_fatal("can't open /etc/passwd\n"); X msg->m_syscall = htons(RSYS_nosys); X msg->m_hdlen = htons(R_MINRMSG + sizeof(long)); X msg->m_totlen = htonl(R_MINRMSG + sizeof(long)); X msg->m_args[0] = htonl(CMD_MOUNT); X write(fdout, msg, R_MINRMSG + sizeof(long)); X write(fdout, byteorder, 4); X while ((ret = read(fdin, buf, BUFSIZ)) > 0) X write(fdout, buf, ret); X close(fdout); X close(fdin); X return; X} X Xturnoff(mntpt) X char *mntpt; X{ X int index, fd; X X index = remoteoff(mntpt); X if (index == -1) X log_fatal("can't unmount remote fs\n"); X close(fd); X} X Xusage() X{ X fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n", X "rmtmnt [-sservicename] -g path", X "rmtmnt [-sservicename] host path", X "rmtmnt"); X exit(1); X} X Xtcpname(sin, host) X struct sockaddr_in *sin; X char *host; X{ X struct servent *servp; X struct hostent *hostp; X int s; X X servp = getservbyname(service ? service : REMOTE_FS_SERVER, "tcp"); X X if (servp == NULL) { X fprintf(stderr, "%s: unknown service\n", REMOTE_FS_SERVER); X exit(1); X } X X hostp = gethostbyname(host); X if (hostp == NULL) { X fprintf(stderr, "%s: unknown host\en", host); X exit(1); X } X bzero((char *)sin, sizeof (struct sockaddr_in)); X bcopy(hostp->h_addr, (char *)&sin->sin_addr, hostp->h_length); X sin->sin_family = hostp->h_addrtype; X sin->sin_port = servp->s_port; X X /* X * Ok, now make sure that the connection will work X */ X if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) { X perror("signals"); X return(-1); X } X s = socket(AF_INET, SOCK_STREAM, 0); X if (s < 0) X return(-1); X alarm(5); X if(connect(s, sin, sizeof(struct sockaddr_in)) < 0) { X alarm(0); X return(-1); X } X alarm(0); X return(s); X} X Xonalrm(sig) X{ X fprintf(stderr, "timeout: "); X} X Xlog_fatal(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X{ X log(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X exit(1); X} X Xlog(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X{ X if (errno) X perror("rmtmnt"); X errno = 0; X fprintf(stderr, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X} SHAREOF chmod 444 remote/rmtmnt.c # # remote/route.c # if [ -f remote/route.c ]; then echo -n 'Hit to overwrite remote/route.c or ^C to quit' read ans rm -f remote/route.c fi sed -e 's/^.//' << \SHAREOF > remote/route.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: route.c,v $ X * Revision 2.2 86/01/05 18:14:47 toddb X * Added a forgotten case to gateway_listen(): S_CORRUPTED. X * X * Revision 2.1 85/12/19 15:53:23 toddb X * Changed declaration of a local variable (sigmask) because it conflicts X * with a 4.3 define. X * X * Revision 2.0 85/12/07 18:22:04 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: route.c,v 2.2 86/01/05 18:14:47 toddb Exp $"; X#include "server.h" X#include X#include X#include X#include X Xextern short current_pid; Xextern short current_ppid; Xextern short gateway_server; Xextern short current_server; Xextern long blocking_servers; Xextern long to_gateway; Xextern long from_servers; Xextern long errno; Xextern boolean i_am_gateway; Xextern boolean i_have_control; Xextern boolean gateway_needs_control; Xextern boolean route_to_gateway; Xextern boolean watch_for_lock; Xextern boolean i_am_asleep; Xextern hosts *host; X X/* X * Reroute to the server whose pid is 'pid'. X */ Xreroute(pid, msg) X register short pid; X register struct message *msg; X{ X if (route_to_gateway) X { X debug5("routing changed from server %d to gateway\n", pid); X route_to_gateway = FALSE; X pid = gateway_server; X } X watch_for_lock = gateway_needs_control = FALSE; X dont_gobble_msg(msg); X X if (pid == current_pid) X log_fatal("reroute myself???\n"); X debug5("%d waking up %d\n", current_pid, pid); X X /* X * If we are the gateway, there may be some servers that are blocking X * on a request. If so, then we lock file descriptor 2 with an X * shared lock. This tells the server to always check to see if X * the lock goes up to an exclusive lock. If so, then the server X * must then return control to the gateway. X */ X if (i_am_gateway) X { X set_label("reading messages"); X i_have_control = FALSE; X if (blocking_servers) X if (flock(2, LOCK_NB | LOCK_SH) < 0) X log_fatal("cannot lock fd 2\n"); X } X X i_am_asleep = TRUE; X if (pid == gateway_server) X say_something(S_THIS_IS_YOURS, gateway_server); X else X wake_up(pid); X slumber(FALSE); X if (! i_am_gateway) X { X /* X * Check for the lock on fd 2. But even if the gateway wants X * control, go ahead an serve this request. X */ X if (flock(2, LOCK_NB | LOCK_EX) < 0) X if (flock(2, LOCK_NB | LOCK_SH) >= 0) X { X debug5("watch for lock on each request\n"); X watch_for_lock = TRUE; X flock(2, LOCK_UN); X } X else X { X debug5("Gateway wants control\n"); X gateway_needs_control = TRUE; X } X else X flock(2, LOCK_UN); X } X} X X X/* X * Tell the gateway something. X */ Xsay_something(cmd, arg) X register long cmd, arg; X{ X gtmsgs gmsg[2]; X register gtmsgs *g = gmsg; X register long len = sizeof(gtmsgs); X X X if (cmd == S_NEWSERVER) /* actually 2 messages */ X { X g->g_server = current_ppid; X g->g_cmd = cmd; X g->g_pid = current_pid; X cmd = S_NEWPROCESS; X g++; X len += sizeof(gtmsgs); X } X g->g_server = current_pid; X g->g_cmd = cmd; X g->g_pid = arg; X X debug5("say: cmd=%d, arg=%d\n", cmd, arg); X if (write(to_gateway, gmsg, len) != len) X log_fatal("pid %d: can't write to gateway!!\n", X current_pid); X} X X/* X * Read message from servers. We do the allocation of space and maintain it. X */ Xgtmsgs *read_gtmsgs() X{ X static gtmsgs *msgs; X static long current_len, X len_needed = 10; X register long red; X register gtmsgs *g; X X /* X * Allocate space for the current read. X */ X if (current_len < len_needed) X { X if (msgs) X msgs = (gtmsgs *)realloc(msgs, X len_needed * sizeof(gtmsgs)); X else X msgs = (gtmsgs *)malloc(len_needed * sizeof(gtmsgs)); X current_len = len_needed; X } X X /* X * Now read the messages. X */ X red = read(from_servers, msgs, (current_len-1) * sizeof(gtmsgs)); X if (red % sizeof(gtmsgs) != 0) X log_fatal("partial message on read = %d\n", red); X red /= sizeof(gtmsgs); X if (red == current_len-1) X len_needed++; X msgs[ red ].g_server = 0; X#ifdef RFSDEBUG X for (g=msgs; g->g_server; g++) X debug14("red: server %d, cmd %d, pid=%d\n", X g->g_server, g->g_cmd, g->g_pid); X#endif RFSDEBUG X return(msgs); X} X X/* X * This process is called to gather incomming messages from servers out X * there with something interesting to say. We return TRUE if we have X * read a message from a process that is relinquishing control, FALSE X * otherwise. X */ Xgateway_listen() X{ X register process *proc; X register gtmsgs *msgs, *g; X short dequeue(); X register short cmd, i, pid, server; X X msgs = read_gtmsgs(); X X errno = 0; X for (g=msgs; g->g_server; g++) X { X pid = g->g_pid; X server = g->g_server; X cmd = g->g_cmd; X X switch(cmd) { X case S_NEWSERVER: /* a new server forked by another server */ X debug5("hear: %d forks new server %d\n", server, pid); X break; X case S_NEWPROCESS: /* a new process is being served */ X proc = add_new_process(0, pid); X proc->p_handler = server; X debug5("hear: pid %d serving pid %d\n", server, pid); X break; X case S_PROCEXIT: /* some server's client did an exit() call */ X debug5("hear: proc exit from server %d: pid=%d\n", X server, pid); X if ((proc = findprocess(pid, -1)) == NULL) X log("can't find pid %d!\n", pid); X else X { X deletelist(&host->h_proclist, proc); X freeproc(proc); X } X break; X case S_I_WOULD_BLOCK: /* server will block on I/O */ X debug5("hear: server %d blocks\n", server); X blocking_servers++; X goto gateway_control; X case S_ALLDONE: /* an existing server is ready to die */ X case S_EOF: /* a server got eof on command socket */ X mourne(); X debug5("hear: server %d %s... ", server, X cmd == S_ALLDONE ? "dead" : "got eof"); X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler == server) X { X debug5("free proc %d...", proc->p_pid); X deletelist(&host->h_proclist, proc); X freeproc(proc); X } X debug5("\n"); X /* fall through */ X case S_THIS_IS_YOURS: /* just relinquish control */ X gateway_control: X /* X * Always unlock when we have control. X */ X flock(2, LOCK_UN); X if (cmd == S_THIS_IS_YOURS) X debug5("hear: server %d gives us control\n", X server); X /* X * Now that we have control, see about dequeing X * a server that is ready to go. If there is one, X * Then change this message so that it looks like X * a message from ourself saying to reroute to X * 'server'. X */ X server = dequeue(); X if (server > 0) X { X debug5("server %d ready to go\n", server); X wake_up(server); X } X else X { X debug5("gateway pid %d continuing\n", X current_pid); X set_label("active"); X i_have_control = TRUE; X } X break; X case S_I_AM_READY: X debug5("hear: server %d ready\n", server); X blocking_servers--; X if (flock(2, LOCK_EX) < 0) X log_fatal("cannot lock fd 2\n"); X queue(server); X break; X case S_CORRUPTED: X log_fatal("corrupted input stream\n"); X break; X default: X log("unknown message from %d = %d\n", server, cmd); X break; X } X } X X return(FALSE); X} X Xwake_up(pid) X long pid; X{ X sendsig(pid, SIGIO); X} X Xsendsig(pid, sig) X long pid, X sig; X{ X register func logger; X extern long log(), log_fatal(); X X change_to_uid(0); X if (kill(pid, sig) < 0) X { X if (errno == ESRCH) X logger = log; X else X logger = log_fatal; X logger("couldn't signal %d w/ sig=%d\n", pid, sig); X return(FALSE); X } X return(TRUE); X} X Xstatic short *server_queue; Xstatic short server_len; Xstatic short last_server; X/* X * Put a server on a queue to be run again. Fifo queue. X */ Xqueue(pid) X register short pid; X{ X if (++last_server > server_len) X { X server_len++; X if (server_queue == NULL) X server_queue = (short *)malloc(sizeof(short)); X else X server_queue = (short *)realloc(server_queue, X server_len*sizeof(short)); X } X server_queue[ last_server - 1 ] = pid; X} X X/* X * Get the first server off the queue. Blech! We have to copy all the X * queue back one. X */ Xshort dequeue() X{ X register short retval, i; X X if (last_server == 0) X return(0); X retval = server_queue[ 0 ]; X for (i=1; i to overwrite remote/server.h or ^C to quit' read ans rm -f remote/server.h fi sed -e 's/^.//' << \SHAREOF > remote/server.h X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: server.h,v 2.0 85/12/07 18:22:12 toddb Rel $ X * X * $Log: server.h,v $ X * Revision 2.0 85/12/07 18:22:12 toddb X * First public release. X * X */ X#include X#include X#include X#include X#include X Xtypedef unsigned char boolean; X X/* X * The maximum number of longs in a message that we accept X */ X#define MAXMSGS ((R_MAXMBUFS*MLEN)/sizeof(long)) X/* X * The name of a host for which we have no record. And the name of the user X * to use if we don't recognize the user on the remote host. X */ X#define BOGUSHOST "unknown host" X#define BOGUSUSER "unknown user" X#define DEFAULTUSER "guest" X X/* X * The uid number below which we reserve for privilaged users. X */ X#define UID_TOO_LOW 20 X X/* X * This is to make the debug? macro work for the server. X * X * The bits and what they turn on are as follows X * 0x00000001 process switching X * 0x00000002 system calls X * 0x00000004 setuid/setgid, umask X * 0x00000008 file descriptor allocation X * 0x00000010 connections X * 0x00000020 server switching X * 0x00000040 nameserver X * 0x00000080 directory nuxi X * 0x00000100 message in and out X * 0x00000200 don't fork child for gateway (good for adb) X * 0x00000400 local/remote file decisions X * 0x00000800 don't remove log file on exit (except exit on error) X * 0x00001000 exec information X * 0x00002000 auto debug for 0x20 (server switching) X * 0x00004000 parsing messages to gateway X */ X#define rmt_debug log X#ifndef RFSDEBUG X#define dumphost() X#endif RFSDEBUG X X/* X * The size of the initial allocation for internal io buffers. X */ X#define BIGBUF (8*1024) X X/* X * other Manifest constants... X */ X#define HOSTNAMELEN 255 X X/* X * Map a file descriptor from the user's fd to our own internal fd. X */ X#define MAPFD(fd, proc) \ X (((unsigned)fd > NOFILE) ? -1 : (proc)->p_fds[ fd ] ) X/* X * requirements for different system calls. X */ X#define NEED_ZIP 0x000 /* don't need anything special */ X#define NEED_CWD 0x001 /* need the current working directory set */ X#define NEED_PERM 0x002 /* need the user and group ids set */ X#define NEED_FD 0x004 /* need a file descriptor allocated */ X#define NEED_2PATH 0x010 /* uses two paths */ X#define NEED_MYSERVER 0x020 /* must be run by the assigned server */ X#define NEED_2REMOTE 0x040 /* both paths must be remote */ X X/* X * Commands to the server sent by external programs (like rmtmnt, to mount X * a remote system. X */ X#define CMD_SERVICE 1 X#define CMD_MOUNT 2 /* here is mount information */ X#define CMD_NEEDMOUNT 3 /* give me mount information */ X#define CMD_WHOAMI 4 /* what uid am I on your host */ X X/* X * Finally, some commands that are sent to the gateway server by other X * servers. X */ X#define S_NEWSERVER 0 X#define S_NEWPROCESS 1 X#define S_ALLDONE 2 X#define S_THIS_IS_YOURS 3 X#define S_PROCEXIT 4 X#define S_EOF 5 X#define S_I_WOULD_BLOCK 6 X#define S_I_AM_READY 7 X#define S_CORRUPTED 8 X X/* X * Macros for getting the address of the paths out of the incomming message. X * Note that path1addr is for system calls that deal with only one path, X * and twopath1addr() and twopath2addr() are for system calls that have X * two paths (in the latter cases, path2 appears in the same position X * as path1 does for single path system calls). X */ X#define path1addr(msg) ((char *)&(msg)->m_args[R_PATHSTART]) X#define twopath1addr(msg) ((char *)(msg) + (msg)->m_args[R_PATHOFF]) X#define twopath2addr(msg) ((char *)&(msg)->m_args[R_PATHSTART]) X X/* X * Macro for preventing getmsg(), and thereby gobble_last_msg() from X * reading the last message. This is used when control is being passed X * from one server to another. X */ X#define dont_gobble_msg(msg) (msg)->m_totlen = 0 X X/* X * Macro for determining whether a stat structure reflects the root inode X * of our machine or not. X */ X#define isroot(p) (p->st_ino == root.st_ino && p->st_dev == root.st_dev) X X/* X * This structure is one-to-one with each local user where the server runs. X * Note that the u_next and u_prev pointers must be located X * in the first and second spots of the structure, respectively so that X * they can be modified by the linked-list routines. X */ Xtypedef struct users_type users; Xstruct users_type { X users *u_next; /* pointers for linked list, both forward... */ X users *u_prev; /* ... and back. */ X char *u_name; /* The ascii name of same. */ X char *u_dir; /* login directory for same */ X char *u_rhosts; /* path of the user's rhost file */ X short u_local_uid; /* A user id number on the local host */ X long u_local_groups[NGROUPS];/* The groups this user belongs to */ X char u_numgroups; /* The number of groups in u_local_groups */ X}; X X/* X * Remote user specification. X */ Xtypedef struct ruser_type rusers; Xstruct ruser_type { X rusers *r_next; X rusers *r_prev; X short r_uid; /* Uid number on remote host ... */ X char *r_name; /* Uid name on remote host ... */ X users *r_user; /* corresponding local user */ X}; X X/* X * This is the important stuff. There is one of these structures for X * each pid that we are providing service to. X */ Xtypedef struct process_type process; Xstruct process_type { X process *p_next; X process *p_prev; X long p_returnval; /* return value from last syscall */ X rusers *p_ruser; /* info about the owner of this pid */ X short p_pid; /* process id number on remote host */ X short p_uid; /* remote uid that was last known */ X short p_handler; /* the handler for this process */ X short p_errno; /* errno for the system call */ X char p_execfd; /* file descriptor of exec file */ X boolean p_execstarted; /* whether we have done first read */ X char p_fds[ NOFILE ];/* fd's assoc. with this pid */ X}; X X/* X * This structure keeps track of the possible hosts that may make a connection X * the the remote fs server. Note that the h_next and hprev pointers must be X * located in the first and second spots of the structure, respectively, X * so that they can be modified by the linked-list routines. X */ Xtypedef struct hosts_type hosts; Xstruct hosts_type { X hosts *h_next; X hosts *h_prev; X char **h_names; /* name (and aliases) of a host */ X rusers *h_rusers; /* the user list for this host */ X users *h_default_user;/* default local user (if defined */ X rusers *h_default_ruser;/* default when the remote user is unknown */ X long h_portnum; /* port number that we connected on */ X char *h_mntpt; /* mount point for this machine */ X process *h_proclist; /* processes we know about on this host */ X struct in_addr h_addr; /* network address */ X union h_bytes { X long hu_mounted; /* non-zero if host has been mounted */ X u_char hu_byteorder[4]; /* byte order for this host */ X } h_bytes; X#define h_mounted h_bytes.hu_mounted X#define h_byteorder h_bytes.hu_byteorder X char h_cmdfd; /* file descriptor for commands */ X boolean h_byteorderok; /* true if byte order same as ours */ X short h_serverpid; /* gateway server for this host */ X}; X X/* X * This structure is the mask structure that the linked list routines use X * to modify any linked-list type of structure. Note that l_next and l_prev X * must be in the first and second spots. X */ Xtypedef struct l_list_type l_list; Xstruct l_list_type { X l_list *l_next; X l_list *l_prev; X long l_data; /* never used */ X}; X X/* X * This structure is for convenience: it simply defines an easy way of X * storing the host/user line found in a .rhost file. X */ Xtypedef struct rhost_type rhost; Xstruct rhost_type { X char *rh_host; X char *rh_user; X}; X X/* X * Each message from the servers to the gateway, is placed into this X * structure, the "gateway message". X */ Xtypedef struct gtmsg_type gtmsgs; Xstruct gtmsg_type { X short g_server; /* server that sent the message. */ X short g_pid; /* pid of whom this message is about */ X short g_cmd; /* what this message is about */ X}; X X/* X * Finally, this is the way we keep database info on the system calls X * themselves. X */ Xtypedef struct syscallmap syscallmap; Xstruct syscallmap { X func s_server; X func s_syscall; X char s_type; X}; X Xrhost *getrhostent(); Xhosts *tcpaccept(); Xhosts *findhostaddr(); Xhosts *findhostname(); Xhosts *newhost(); Xl_list *toplist(); Xl_list *bottomlist(); Xl_list *addlist(); Xl_list *deletelist(); Xprocess *newprocess(); Xprocess *findprocess(); Xprocess *change_to_proc(); Xprocess *add_new_process(); Xusers *finduid(); Xusers *findusername(); Xusers *newuser(); Xrusers *findremuid(); Xrusers *findrusername(); Xrusers *newruser(); Xchar **newname(); Xchar *copy(); Xchar *malloc(); Xchar *realloc(); Xchar *get_data_buf(); Xshort *newshortlist(); SHAREOF chmod 444 remote/server.h # # remote/serverdata.c # if [ -f remote/serverdata.c ]; then echo -n 'Hit to overwrite remote/serverdata.c or ^C to quit' read ans rm -f remote/serverdata.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdata.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdata.c,v $ X * Revision 2.0 85/12/07 18:22:20 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdata.c,v 2.0 85/12/07 18:22:20 toddb Rel $"; X#include "server.h" X#include X#include X#include X#include X X/* X * system calls. X */ Xlong access(), chdir(), chmod(), chown(), close(), dup(), execve(), X fchmod(), fchown(), fcntl(), flock(), fork(), fstat(), fsync(), X ftruncate(), ioctl(), link(), lseek(), lstat(), mkdir(), X mknod(), open(), read(), readlink(), rename(), rmdir(), X stat(), symlink(), truncate(), unlink(), utimes(), X write(), X/* X * ...and our own routines to set up for the system calls. X */ X noop(), s_access(), s_dup(), s_execinfo(), s_execread(), s_exit(), X s_fcntl(), s_fd1(), s_fd1_plus(), s_fork(), s_ioctl(), s_lseek(), X s_open(), s_path1(), s_path1_plus(), s_path2(), s_read(), X s_readlink(), s_stat(), s_utimes(), s_write(); X Xsyscallmap smap[] = { X s_fork, noop, NEED_ZIP, /* RSYS_fork */ X s_read, read, NEED_ZIP, /* RSYS_read */ X s_write, write, NEED_ZIP, /* RSYS_write */ X s_open, open, NEED_CWD X |NEED_MYSERVER X |NEED_PERM X |NEED_FD, /* RSYS_open */ X s_fd1, close, NEED_ZIP, /* RSYS_close */ X noop, noop, NEED_CWD X |NEED_PERM X |NEED_FD, /* RSYS_creat */ X s_path2, link, NEED_CWD X |NEED_MYSERVER X |NEED_2PATH X |NEED_2REMOTE X |NEED_PERM, /* RSYS_link */ X s_path1, unlink, NEED_CWD|NEED_PERM, /* RSYS_unlink */ X s_path1, chdir, NEED_MYSERVER X |NEED_CWD X |NEED_PERM X |NEED_MYSERVER, /* RSYS_chdir */ X s_path1_plus, mknod, NEED_CWD|NEED_PERM, /* RSYS_mknod */ X s_path1_plus, chmod, NEED_CWD|NEED_PERM, /* RSYS_chmod */ X s_path1_plus, chown, NEED_CWD|NEED_PERM, /* RSYS_chown */ X s_stat, stat, NEED_CWD|NEED_PERM, /* RSYS_stat */ X s_lseek, lseek, NEED_ZIP, /* RSYS_lseek */ X s_access, access, NEED_CWD|NEED_PERM, /* RSYS_access */ X s_stat, lstat, NEED_CWD|NEED_PERM, /* RSYS_lstat */ X s_dup, dup, NEED_FD, /* RSYS_dup */ X s_ioctl, ioctl, NEED_ZIP, /* RSYS_ioctl */ X s_path2, symlink, NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_symlink */ X s_readlink, readlink, NEED_CWD|NEED_PERM, /* RSYS_readlink */ X s_stat, fstat, NEED_ZIP, /* RSYS_fstat */ X s_dup, dup, NEED_FD, /* RSYS_dup2 */ X s_fd1_plus, fcntl, NEED_ZIP, /* RSYS_fcntl */ X s_fd1, fsync, NEED_ZIP, /* RSYS_fsync */ X noop, noop, NEED_ZIP, /* RSYS_readv */ X noop, noop, NEED_ZIP, /* RSYS_writev */ X s_fd1_plus, fchown, NEED_PERM, /* RSYS_fchown */ X s_fd1_plus, fchmod, NEED_PERM, /* RSYS_fchmod */ X s_path2, rename, NEED_MYSERVER X |NEED_2REMOTE X |NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_rename */ X s_path1_plus, truncate, NEED_CWD|NEED_PERM, /* RSYS_truncate */ X s_fd1_plus, ftruncate,NEED_ZIP, /* RSYS_ftruncate */ X s_fd1_plus, flock, NEED_ZIP, /* RSYS_flock */ X s_path1_plus, mkdir, NEED_CWD|NEED_PERM, /* RSYS_mkdir */ X s_path1, rmdir, NEED_CWD|NEED_PERM, /* RSYS_rmdir */ X s_utimes, utimes, NEED_CWD|NEED_PERM, /* RSYS_utimes */ X s_exit, noop, NEED_ZIP, /* RSYS_exit */ X s_fork, noop, NEED_ZIP, /* RSYS_Vfork */ X s_execinfo, noop, NEED_MYSERVER X |NEED_CWD X |NEED_PERM, /* RSYS_execinfo */ X s_execread, noop, NEED_PERM, /* RSYS_execread */ X noop, noop, NEED_ZIP, /* RSYS_execve */ X noop, noop, NEED_ZIP, /* RSYS_nosys */ X s_lseek, lseek, NEED_ZIP, /* RSYS_qlseek */ X}; X Xchar *syscallnames[] = { X "fork", X "read", X "write", X "open", X "close", X "creat", X "link", X "unlink", X "chdir", X "mknod", X "chmod", X "chown", X "stat", X "lseek", X "access", X "lstat", X "dup", X "ioctl", X "symlink", X "readlink", X "fstat", X "dup2", X "fcntl", X "fsync", X "readv", X "writev", X "fchown", X "fchmod", X "rename", X "truncate", X "ftruncate", X "flock", X "mkdir", X "rmdir", X "utimes", X "exit", X "vfork", X "execinfo", X "execread", X "execve", X "nosys", X "quick lseek" X}; X Xchar hostname[ HOSTNAMELEN ];/* our host name */ Xchar mntpt[ MAXPATHLEN ]; /* mount point for client */ Xchar *program; /* name of this program */ Xchar *last_argaddr; /* last address that we can scribble on */ Xchar *service = REMOTE_FS_SERVER; /* name of alternate internet service */ Xchar *stdlogfile = "/usr/tmp/rfs_log"; /* log file for server */ Xchar *logfile; Xlong serviceport; /* port number for service */ Xlong remote_debug; /* level of debug output */ Xshort current_uid; /* whatever uid we are, right now */ Xshort current_pid; /* whatever pid we are, right now */ Xshort current_ppid; /* our parent server */ Xshort current_umask; /* whatever umask we have, right now */ Xshort current_server; /* server that has control right now */ Xshort gateway_server; /* pid of our gateway */ Xshort last_sentry; /* previous sentry server (if non-zero) */ Xlong fds_in_use; /* number of total file descriptors open */ Xlong to_gateway; /* file descriptor for messages to gateway */ Xlong so_listen; /* socket for listening for connections */ Xlong from_servers; /* file descriptor for messages from servers */ Xlong blocking_servers; /* number of servers waiting for I/O */ Xhosts *hostlist; /* all the hosts we know of */ Xhosts *host; /* the current host that we talk to */ Xhosts *thishost; /* host pointer for this machine */ Xusers *userlist; /* all the users on this host we know of */ Xusers *default_user; /* default user to map unknown clients to */ Xprocess *wildcard; /* wildcard process for easy requests */ Xboolean i_am_gateway = TRUE; /* whether we are the gateway server */ Xboolean i_have_control = TRUE; /* whether the gateway server has control of */ X /* the command socket */ Xboolean i_am_asleep; /* whether we are sleeping or not */ Xboolean gateway_needs_control; /* True if gateway wants control back */ Xboolean watch_for_lock; /* True if we need to watch for lock on fd 2 */ Xboolean route_to_gateway; /* True if we should route to gateway */ Xboolean in_root_directory = TRUE;/* whether we are at root directory or not */ Xstruct stat filetypes[ NOFILE ]; /* file types for open files */ X Xchar byteorder[4] = { BYTEORDER }; Xlong catch(), X nameserver(), X wakeup_call(), X alarmsig(); X Xstruct sigvec sig_continue = { X wakeup_call, X 1<<(SIGIO -1), X 0 X}; X Xstruct sigvec sig_ignore = { X (int (*)())SIG_IGN, X 1<<(SIGHUP -1), X 0 X}; X Xstruct sigvec sig_alarm = { X alarmsig, X 1<<(SIGALRM -1), X 0 X}; X Xstruct sigvec sig_name = { X nameserver, X 1<<(SIGURG -1), X 0 X}; X Xstruct sigvec sig_vec = { X catch, X (1<<(SIGINT -1)) X |(1<<(SIGQUIT-1)) X |(1<<(SIGBUS-1)) X |(1<<(SIGILL-1)) X |(1<<(SIGSEGV-1)) X |(1<<(SIGPIPE-1)) X |(1<<(SIGSYS-1)) X |(1<<(SIGTERM-1)) X |(1<<(SIGTTIN-1)) X |(1<<(SIGTTOU-1)) X |(1<<(SIGXCPU-1)) X |(1<<(SIGXFSZ-1)) X |(1<<(SIGVTALRM-1)), X 0 X}; X X#ifdef RFSDEBUG X Xlong newdebug(); X Xstruct sigvec sig_debug = { X newdebug, X (1<<(SIGTRAP -1)), X 0 X}; X#endif RFSDEBUG X Xstruct stat root; /* stat info for root directory */ SHAREOF chmod 444 remote/serverdata.c # # remote/serverdir.c # if [ -f remote/serverdir.c ]; then echo -n 'Hit to overwrite remote/serverdir.c or ^C to quit' read ans rm -f remote/serverdir.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdir.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdir.c,v $ X * Revision 2.0 85/12/07 18:22:28 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdir.c,v 2.0 85/12/07 18:22:28 toddb Rel $"; X#include "server.h" X#include X#include X#include X Xextern hosts *host; Xextern long errno; Xextern char byteorder[]; Xextern struct stat filetypes[]; X X/* X * Check to see type open file type... we may have to massage input X * it if the user wants to read this file descriptor and it is a directory. X */ Xcheckfiletype(fd) X register int fd; X{ X struct stat statb, *statp = &statb; X X if (fd < 0) X return; X fstat(fd, statp); X filetypes[ fd ] = statb; X} X X/* X * If byte-ordering is different between this machine and our client, X * the directories must be massaged into the right byte order. X */ Xfixdir(fd, buf, size) X register long size, X fd; X register char *buf; X{ X register struct direct *dirp; X register char *next, *last; X register u_char *clientorder = host->h_byteorder; X short fixshort(); X X if (size < 0) X return(errno); X if (fd >= NOFILE || (filetypes[fd].st_mode & S_IFDIR) == 0) X return(0); X X /* X * we don't know this client's byteorder... can't do it right X */ X if (!host->h_mounted) X return(EIO); X dirp = (struct direct *)buf; X last = buf; X debug7("nuxi directory entry buf=0%x, size=%d, end @%x\n", X buf, size, buf+size); X while(last < buf + size && dirp->d_reclen) X { X dirp = (struct direct *)last; X next = last + dirp->d_reclen; X X debug7("dir @0x%x (next+%d @0x%x): %x %x %x %s -->", X last, dirp->d_reclen, next, X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X dirp->d_ino = fixlong(clientorder, &dirp->d_ino); X dirp->d_reclen = fixshort(clientorder, &dirp->d_reclen); X dirp->d_namlen = fixshort(clientorder, &dirp->d_namlen); X debug7(" %x %x %x %s\n", X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X last = next; X } X return(0); X} X Xfixlong(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X long result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0] ] = from[ srvo[0] ]; X to[ clto[1] ] = from[ srvo[1] ]; X to[ clto[2] ] = from[ srvo[2] ]; X to[ clto[3] ] = from[ srvo[3] ]; X return(result); X} X Xshort fixshort(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X short result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0]&0x1 ] = from[ srvo[0]&0x1 ]; X to[ clto[1]&0x1 ] = from[ srvo[1]&0x1 ]; X return(result); X} SHAREOF chmod 444 remote/serverdir.c