slugnet - Multiple user conferencing system: Part 3 of 6

James R. Purdon III purdon at athena.mit.edu
Fri Dec 21 03:44:51 AEST 1990


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 at 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 <stdio.h>
#include <fcntl.h>

#ifdef SUNOS
#define O_FSYNC O_SYNC
#endif

#if defined( SYSV3 ) && !defined( UNICOS )

#include <filehdr.h>
#include <scnhdr.h>

#endif 

#ifdef SYSV2

#include <filehdr.h>
#include <scnhdr.h>
#include <ldfcn.h>

#endif SYSV2

#include <unistd.h>
#ifdef INTERLAN
#include <interlan/il_types.h>
#else
#include <sys/types.h>
#endif
#include <sys/stat.h>
#include <signal.h>
#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



More information about the Alt.sources mailing list