This documents the security of dwun. For information on securing dwun, see the 
HTML docs (doc/html/).

TODO: command-line/config file, exec, open/stat and f-friends

Contents:
	0. Network
	1. Logging
	2. User input
		2.1 normal
		2.2 admin
	3. Onconnect/ondisconnect

0. Network
----------

All data, including passwords, are sent in plaintext.

1. Logging
----------

notice, notice_err, notice_errdebug, notice_debug

If your system has vsnprintf() and syslog(), it uses those (by default). 
Otherwise it writes to a logfile using vfprintf().

vsnprintf() writes into a buffer allocated by malloc() at the start of the 
program and abides by the maximum buffer size.

2. User input
-------------

All data from clients is retrieved using getline() [child.c]. This function 
malloc()'s a buffer and passes it on to sok_getstring() [socket.c] which 
respects the maximum buffer size.

The only function that calls getline() is getcommand(). It looks for a ' ' in 
the buffer, and if one is present copies the data after the space into a new 
buffer, which is dynamically allocated (with strdup()).

After some strcasecmp()'s, the first buffer is free()'d.

inputhandler() and ad_handler() call getcommand(). They have access to the 
buffer of the data after the space (argument to getcommand()).

2.1. Normal
-----------

For inputhandler(), if the command wasn't USER or PASS any argument is free()'d 
and ignored.

For USER, we create a new reference to the buffer (user).

For PASS (after first checking we already have the username) we pass the user 
and the new buffer (which is the argument to PASS) to authentication().

authentication() passes the user to notice(). (See section 1.)

authentication() calls inpass(), giving it the user and authfile and specifying 
':' to separate user/crypted pass in the authfile. For each line until a match
is found it calculates the length of the username in the authfile from the start
of the line until the first ':'. It then compares this length to the length of
the supplied username and then with 
strncmp(supplied-user, start-of-line-in-authfile, length-of-username). If a
match is found, the password (data after : until \n) for the username is 
returned. 

inpass() will reject a username if it contains non-alphanumeric characters.

inputhandler() zeroes the password space as soon as possible. getcommand()
checks if the command was COM_PASS, and if so zeroes out the entire temporary
buffer.

check_pass() is given the user-supplied password and the crypted password from 
inpass(). We then do crypt(user-supplied-pass, authfile-crypt-pass) because
crypt will get the salt from the first two characters of the crypted pass. We
compare the result with the authfile-crypt-pass. Plain crypt only pays attention
to the first 8 characters of a password.

2.2. Admin
----------

ad_handler gets a list of all clients currently attached to the server. When the
admin gives a command with an argument (which is either a username in the form
%user or a numerical pid) we use the list as it was at the time of the last LIST
command. This is so, for example, "LOCK pid" has the desired effect even if the
user has since disconnected. If no LIST has been done we'll just get a one now. 
In theory, if between the time a LIST is done and a KILL pid (e.g.) is done the 
given client has since left and so many clients have come/gone that we've cycled
through the limit of pids on the system we could end up killing the wrong
client. (Or indeed to pppd process). However, even on a machine where processes
are spawned and die at a -fantastic- rate, this is going to take hours. Note 
that this is exactly the same risk as if you were to run ps from your shell and
then type kill {pid}. It's just not going to be a problem in real life.

If the user-specified argument begins with %, the data after the % is copied
into a new buffer. Otherwise we use the username matching the given pid. (From
the current list of users). In any case the buffer with data from getcommand is
quickly free()'ed.

For KILL, we call ad_kill_user or ad_kill_pid depending on the argument. For a
%user argument we send SIGHUP to all the pids in the list of all current clients
whose username match our argument. Otherwise we kill the given pid.

For LOCK and UNLOCK we call inpass(). The security of this is explained in 2.1. 
ZAP just does a LOCK and KILL.

3. Onconnect/ondisconnect
-------------------------

These can have an argument of the users username and/or IP address and/or pid of
the child process. Makeauth and the inpass() function in child.c only allow 
usernames which are made entirely of alphanumeric characters. (a-z, A-Z, 0-9). 
This way it is not possible for the username in an onconnect or ondisconnect 
command to contain shell metacharacters.
