Path: utzoo!attcan!utgpu!cs.utexas.edu!usc!snorkelwacker.mit.edu!bloom-picayune.mit.edu!athena.mit.edu!purdon From: purdon@athena.mit.edu (James R. Purdon III) Newsgroups: alt.sources Subject: slugnet - Multiple user conferencing system: Part 3 of 6 Message-ID: <1990Dec20.164451.25293@athena.mit.edu> Date: 20 Dec 90 16:44:51 GMT References: <1990Dec20.163739.24869@athena.mit.edu> Sender: news@athena.mit.edu (News system) Organization: Massachusetts Institute of Technology Lines: 681 The slugnet program is a multiple-user, interactive conferencing facility. It currently runs under a variety of System V-based and BSD-based operating systems (although certain functions may not be possible under some of these operating systems). Cut here------------------------------------------------------------------- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./slugnet.doc` then echo "writing ./slugnet.doc" cat > ./slugnet.doc << '\End\Of\Shar\' .TL @(#)slugnet.doc 1.2 .AU James Purdon .LP .B Introduction .LP The slugnet program is a multiple-user, interactive conferencing facility. It currently runs under SUNOS, UNICOS, and ULTRIX, as well as on machines running UNIX System V 2.x and 3.x (although certain functions may not be possible under some of these operating systems). .B History .LP I first got the idea for slugnet in 1985, after a short viewing of RELAY, the BITNET conferencing facility. Although I had written a multiple-user conferencing facility with multiple channels, private conferences, conference locking, and paging under the MUSIC/SP operating system at the University of Georgia, something about the RELAY format inspired me to write a short program (in FORTG1) which had some of the look and feel of RELAY. .PP Of course, user-written talk programs weren't exactly encouraged at UGA, so I played with it a bit, showed it to a few folks, and then abandoned it. That code may still be lurking about on one of my PC floppies, but it is for the most part lost. .PP In 1986 I gained access to another machine, a Control Data Corporation Cyber 180/865 running NOS 2.x (my memory is a bit hazy here). In order to understand it better, I decided to write a conferencing system in FTN5 similar to the one I had done before on MUSIC. Again, I showed it to a few folks, but there was little interest. There were already some system programs that were functionally equivalent, which ran with great efficiency on the system's NPUs. After setting up the program in a script that would automatically build it, I again abandoned it (however, the code to this version is a part of this package and is in the file slugnet.n). .PP Shortly after I had completed the FTN5 version, I obtained a copy of Microsoft Quick C for my PC XT in order to learn c. At the time I was running a multiple-user, multitasking OS on my PC called Wendin Dos, and I decided for a lark to port slugnet to c. .PP Late in 1987 I was able to upgrade my PC XT to a PC AT and for the first time I was able to run UNIX. Again I ported slugnet as a learning experience. .PP Since then, I have ported slugnet just about every time I have learned a new operating system or encountered a different hardware platform. Its been quite helpful in illustrating where a particular UNIX-variant is different from what I'm accustomed too. The latest modifications I've made allow it to run as a server under TCP/IP, so that users do not require a login in order to use it. .PP Well its a new decade and I have grand new ideas for another program. It seems a shame to waste the effort I put into slugnet, and I really like the name, so I thought I'd post it to the net for posterity. .B "How slugnet Works" .LP Slugnet uses files, lots of files. One for each active user, a central directory, and files for things like file-locking, news and command definitions. Each time a user tries to read incoming messages, there is a disk access. Every time a user writes a message, there is a disk access for each recipient. If the user selects to read messages continuously, there is a disk access each interval specified by the "set delay" command. If you are on a system with fast i/o, you won't be bothered, but otherwise you may suffer a performance penalty. .PP There is a local program "slugnet" and a network server "slugnetd". Neither requires the other to be present, and both use the same files for communication. If you don't want to service the net, you don't have to. .PP By default, slugnet is setuid to whatever account owns slugnet. I recommend creating its own account rather than using root. It is setuid to protect the privacy of user messages and to keep malicious users from wreaking havoc. You could try to use ignorance to protect the files, if you don't want to run it setuid. .PP Running slugnet setuid brings up some problems. There are a series of commands the user can execute to do things like save configurations, message buffers, and incoming messages, run slugnet scripts, and read in files to be transmitted as messages (of course none of these commands make sense for users of the network server and should not be permitted). In UNIX System V a user process may switch back and forth between the real and effective uid but under some BSD-based systems this is not possible. Under these systems it is necessary to limit what the user may do (in fact, it is the default state for all systems). .PP Slugnet controls the users access to various commands through a privilege mechanism. Default privileges are assigned in the routine getcfg and defined in slugnet.h. These may be over-ridden by a pri or a net entry in the slugnet configuration file for slugnet and slugnetd respectively. The privileges are described by a single letter and are as follows: .PP a : administrative commands. .PP b : broadcast allowed. .PP d : redirection allowed. .PP f : file access allowed. .PP j : join command allowed. .PP n : set name command allowed. .PP p : private messages allowed. .PP r : ring command allowed. .PP s : shell access allowed. .LP Of these, d, f, and s are affected by the setuid problem. .PP The number of users slugnet can support is limited only by the number of processes on your system. Each user executes his/her own copy of the program. .B "Configuring slugnet" .LP Slugnet reads a configuration file in the slugnet directory named "slugsys.dat". This file contains lines of the following format: .ce 1 keyword=value .LP The valid keywords and options follow: .LP .B acc Access mode (default "immediate"). In slugnet's sorted past, it once had its own login routine. Access was granted to new users based on the value of this keyword. The acceptable values were "immediate", "delayed", and "denied." .LP .B act Accounting file name (default "slugact.dat"). The file in the slugnet directory that contains accounting records. .LP .B bgn Prelogin file name (default "slugbgn.dat"). This once served as slugnet's prelogin file. Since the login routines were removed, it's not much different than news. .LP .B bil Billing mode (default "off"). Obsolete. Acceptable values are "on" or "off". .LP .B blf Billing file name (default "slugbil.dat"). Obsolete. Where user billing information was kept. .LP .B def Definition file name (default "slugdef.dat"), user or system. If you run slugnet on System V with user file privileges, this is the default name of the user definition file (where users define their own commands). For slugnetd, and slugnet on BSD-based systems, it is a file for system-wide definitions. .LP .B dir Directory file name (default "slugdir.dat"). Obsolete. Where user registration information was kept. .LP .B hlp Help file name (default "slughlp.dat"). The help file. New topics may be added, but not after the line that begins with the string "*EOF:". Each topic should be indicated by a line containing an asterisk, the topic name in upper case, and a trailing colon. .LP .B jsn Jsn file name (default "slugjsn.dat"). The jsn is part of the unique identifier assigned to every slugnet user (the host name is the remaining part). .LP .B log Use login mode (default "off" ). Obsolete. Acceptable values are "on" or "off". .LP .B mod Modem initialization string (default "ATZ S0=1 X1 E0 V0 S2=128"). Very obsolete. .LP .B new News file name (default "slugnew.dat"). A file that is displayed after the user connects (in early versions, after the user logged in). .LP .B net Permission set for slugnetd (default PRIVS). See above for details. .LP .B por Communications port. Obsolete. .LP .B pri Permission set for slugnet (default PRIVS). See above for details. .LP .B pro User/system prologue file (default "slugpro.dat"). Commands to be executed once user has connected to slugnet. .LP .B usr User file name (default "slugusr.dat"). This is the table of currently active users. .LP .B val Validation file (default "slugval.dat"). Obsolete. Where login information was kept. .PP You might wish to create a definition file to make things easier for users who might be used to other conferencing systems. Here is a copy of mine: .br * .br * for IRC users .br * .br /bye=exit; .br /expert=set novice off; .br /irc=set continuous on; .br /join=join; .br /names=show confer; .br /nick=set name; .br /quit=quit; .br /who *=show members; .br /who=show confer; .br * .br * abbreviations .br * .br se conf=set configuration; .br se cont=set continuous; .br se def=set definition; .br se del=set delay; .br se echop=set echoplex; .br se e=set echo; .br se l=set login; .br se na=set name; .br se no=set novice; .br se prol=set prolog; .br se prom=set prompt; .br se r=set ring; .br se t=set timer; .br se w=set wait; .br sh b=show buffer; .br sh confe=show confer; .br sh confi=show configuration; .br sh h=show hosts; .br sh l=show logins; .br sh m=show members; .br sh m=show members; .B "Administrative commands" .LP Currently, slugnet has only one administrative command, "show all", which shows all the users on all the conferences whether they are invisible or not. The earliest versions had another command, which began with a "$" and contained a target jsn and command. When executed, it forced the target jsn to execute the command (this is, in fact how the ring command works, by forcing the target jsn to execute the bell command). Since the owner of slugnet (but not slugnetd) has access to the shell, and owns all slugnet and slugnetd process, I removed the second command as unnecessary. If you need to kill a user, use "show all" to get his/her pid, and use the shell escape and the Unix kill command to send it a signal - I recommend "kill -1". .PP Slugnet needs very little in the way of maintenance. The accounting file should be flushed at regular intervals and the status of the network server ought to be checked once in a while. I also try to collect any error messages slugnetd may issue. .PP I've changed my rc.local to start up slugnetd on reboot by adding the following line: echo 'rm slugusr.dat; /usr/local/bin/slugnetd &' | su - slugnet >/dev/null .B "Access Control" .LP Neither slugnet or slugnetd provide access control. If you desire to add your own access control, I suggest that it be added into slugnet.c. The easiest thing to do might be to use some of the obsolete keywords in getcfg.c (like val) to point to a validation file and use a grep to see if a particular host or user was validated. When creating a validation mechanism, it is important to note that for remote users, only the host name can be validated (you might want to see how the "set login" command attempts to validate remote users). .B "Suggestions for modifications" .LP 1. A slugnet-specific client would be very nice, as it would solve all setuid-related problems. .LP 2. I worked a bit on a distributed-server model (not quite entirely unlike IRC) but abandoned it when it became clear to me that the server would have to be changed in a way that I felt was unfriendly to remote users. My hacks are set off by the def SERVER. If you compile slugnetd with SERVER, you'd better have some sort of access control. .LP 3. I suppose that conference and server operators might be nice, but I think they are more trouble than they are worth. If you need to control your users that much, you probably shouldn't be running slugnet. .B "Accounting file format" .LP All fields are separated by colons. .br Field 1: login@host .br Field 2: jsn .br Field 3: bytes input .br Field 4: bytes output .br Field 5: login time in seconds from 1970 .br Field 6: logout time in seconds from 1970 .br Field 7: connect time in seconds .br Field 8: day name, month, day, military time, and year. \End\Of\Shar\ else echo "will not over write ./slugnet.doc" fi chmod 400 ./slugnet.doc if [ `wc -c ./slugnet.doc | awk '{printf $1}'` -ne 11723 ] then echo `wc -c ./slugnet.doc | awk '{print "Got " $1 ", Expected " 11723}'` fi if `test ! -s ./slugnet.h` then echo "writing ./slugnet.h" cat > ./slugnet.h << '\End\Of\Shar\' /* @(#)slugnet.h 1.13 */ #include "copyright.h" #include #include #ifdef SUNOS #define O_FSYNC O_SYNC #endif #if defined( SYSV3 ) && !defined( UNICOS ) #include #include #endif #ifdef SYSV2 #include #include #include #endif SYSV2 #include #ifdef INTERLAN #include #else #include #endif #include #include #ifdef INTERLAN #define SIGCHLD SIGCLD #define SIGURG SIGUSR2 #endif INTERLAN #define ON 1 #define OFF 0 #define CRLF 1 #define NOCRLF 0 #define BS 8 #define CR 13 #define DEL 127 #define LF 10 #define CFRLEN 32 #define FLNMLN 16 #define JSNLEN 5 #define LINLEN 80 #define NAMLEN 32 #define UNLEN 8 #define HOSTLEN 64 #define PIDLEN 32 #define MODELN 2 #define ADD 0 #define ALLOW 1 #define DELAY 2 #define DENY -1 #define RETRY -2 #define ADMIN 1 #define DEBUG 0 #define LOGIN 1 #define MSGLEN 2048 #define PRMLEN 34 #define DIRLEN 80 #define TIMEOUT 5 #define BLANKS " " char *strcat(),*strcpy(),*strncpy(),*strchr(),*strrchr(); #ifdef BSD4 char *sprintf(); #endif BSD4 int hungup; int stopscroll; struct slugdir { char name[ NAMLEN ]; char un[ UNLEN ]; char jsn[ JSNLEN ]; char confer[ CFRLEN ]; char rcvfil[ FLNMLN ]; char host[ HOSTLEN ]; char pid[ PIDLEN ]; char mode[ MODELN ]; }; /* default privileges */ #ifdef SYSV2 #ifndef NETWORK #define PRIVS "_bfjnprs" #else #define PRIVS "_bjnpr" #endif #endif SYSV2 #ifdef SYSV3 #ifndef NETWORK #define PRIVS "_bfjnprs" #else #define PRIVS "_bjnpr" #endif #endif SYSV3 #ifdef BSD4 #ifndef NETWORK #define PRIVS "_bjnpr" #else #define PRIVS "_bjnpr" #endif #endif BSD4 #ifdef ULTRIX #ifndef NETWORK #define PRIVS "_bjnpr" #else #define PRIVS "_bjnpr" #endif #endif ULTRIX \End\Of\Shar\ else echo "will not over write ./slugnet.h" fi chmod 400 ./slugnet.h if [ `wc -c ./slugnet.h | awk '{printf $1}'` -ne 1864 ] then echo `wc -c ./slugnet.h | awk '{print "Got " $1 ", Expected " 1864}'` fi if `test ! -s ./slugnet.mk` then echo "writing ./slugnet.mk" cat > ./slugnet.mk << '\End\Of\Shar\' # # @(#)slugnet.mk 1.7: makefile for $(SLUGNET) # # Empty macros are set by calling makefile # SLUGBIN = SLUGDIR = SLUGUID = OS = SLUGNET = MAN = NETFLG = # SLGFLG = -DSLUGDIR=\"$(SLUGDIR)\" CFLAGS = $(OS) $(SLGFLG) $(NETFLG) # DATA = slughlp.dat DOCS = Readme slugnet.1 slugnetd.1 slugnet.doc slugnet.n HEADERS = copyright.h net.h slugnet.h MAKES = Makefile slugnet.mk OBJECTS = call_socket.o callbyaddr.o callbyhost.o chgusr.o cleanup.o\ clnusr.o establish.o find.o get_connect.o getcfg.o getjsn.o lock.o\ lower.o main.o rdline.o receive.o repchar.o send_file.o setjsn.o\ sighang.o sigquit.o sigstop.o sigterm.o sigtstp.o sigurg.o slugnet.o\ strnicmp.o task.o transmit.o unlock.o verify.o SOURCES = call_socket.c callbyaddr.c callbyhost.c chgusr.c cleanup.c\ clnusr.c establish.c find.c get_connect.c getcfg.c getjsn.c lock.c\ lower.c main.c rdline.c receive.c repchar.c send_file.c setjsn.c\ sighang.c sigquit.c sigstop.c sigterm.c sigtstp.c sigurg.c slugnet.c\ strnicmp.c task.c transmit.c unlock.c verify.c $(SLUGNET): $(OBJECTS) cc $(OBJECTS) $(LDFLAGS) -o $(SLUGNET) # # routines # call_socket.o: net.h call_socket.c callbyaddr.o: net.h callbyaddr.c callbyhost.o: net.h callbyhost.c cleanup.o: net.h cleanup.c chgusr.o: slugnet.h chgusr.c establish.o: net.h establish.c find.o: slugnet.h find.c get_connect.o: net.h get_connect.c getcfg.o: slugnet.h getcfg.c getjsn.o: slugnet.h getjsn.c lock.o: slugnet.h lock.c lower.o: slugnet.h lower.c main.o: net.h main.c slugnet.o: slugnet.h slugnet.c rdline.o: slugnet.h rdline.c receive.o: slugnet.h receive.c repchar.o: slugnet.h repchar.c send_file.o: slugnet.h send_file.c setjsn.o: slugnet.h setjsn.c sighang.o: slugnet.h sighang.c sigquit.o: slugnet.h sigquit.c sigstop.o: slugnet.h sigstop.c sigterm.o: slugnet.h sigterm.c sigtstp.o: slugnet.h sigtstp.c sigurg.o: slugnet.h sigurg.c strnicmp.o: slugnet.h strnicmp.c task.o: net.h task.c transmit.o: slugnet.h transmit.c unlock.o: slugnet.h unlock.c verify.o: net.h verify.c clean: @echo "Removing objects..." @rm -f $(OBJECTS) install: $(SLUGDIR) $(SLUGBIN) @echo "Installing $(SLUGNET)..." cp $(SLUGNET) $(SLUGBIN)/$(SLUGNET) chown $(SLUGUID) $(SLUGBIN)/$(SLUGNET) @size $(SLUGBIN)/$(SLUGNET) chmod u+s $(SLUGBIN)/$(SLUGNET) chmod oug+x $(SLUGBIN)/$(SLUGNET) cp slughlp.dat $(SLUGDIR)/slughlp.dat chmod og-w $(SLUGDIR)/slughlp.dat chmod u+w $(SLUGDIR)/slughlp.dat chmod uog+r $(SLUGDIR)/slughlp.dat chown $(SLUGUID) $(SLUGDIR)/* @echo "Installing man page for $(SLUGNET)..." cp $(SLUGNET).1 $(MAN)/$(SLUGNET).1 chmod og-w $(MAN)/$(SLUGNET).1 chmod u+w $(MAN)/$(SLUGNET).1 chmod uog+r $(MAN)/$(SLUGNET).1 # # if slugnet is NOT setuid $(SLUGUID), following statement should be # uncommented. # # chmod oug+rw $(SLUGDIR) $(SLUGBIN): mkdir $(SLUGBIN) $(SLUGDIR): mkdir $(SLUGDIR) # # tar # slugtar: $(DATA) $(DOCS) $(HEADERS) $(MAKES) $(SOURCES) tar -cvf slugtar $(DATA) $(DOCS) $(HEADERS) $(MAKES) $(SOURCES) \End\Of\Shar\ else echo "will not over write ./slugnet.mk" fi chmod 400 ./slugnet.mk if [ `wc -c ./slugnet.mk | awk '{printf $1}'` -ne 3035 ] then echo `wc -c ./slugnet.mk | awk '{print "Got " $1 ", Expected " 3035}'` fi echo "Finished archive 3 of 6" exit