Subject: Re: Threaded

From: Alain Magloire <[email-masked]>
Date: Tue, 16 Dec 1997 11:48:45 -0500 (EST)

Bonjour

:  looked through the wu code a few months ago.. with plans to thread it.
: After spending a couple hours, it became apparent that it would be easier
: to start from scratch.

The way the code is done with seteuid () bouncing on and off and
sigjumps, yes indeed, very hard.

: Especially if you want to maintain regular unix
...
: machine is decent.... In the end i had to end up writing my own.

concurent programming or OO are other styles of programming.
Doing this in any old C code, you'll need to rewrite
major parts.

The big problem whith Thread is that it doesn't scale
well, on a major site whith +700 connections, threads would
collapse.

: 
: Besides, doing the security on it for regular user type logins wouldnt be
: trivial... compared to chroot() anyway. Even though its per process, and
: its not perfect.. its alot easier then keeping that state info.
: 

I don't see why Thread FTP should not use chroot () ?
And the same goes if you use Async I/O (NON_BLOCKING)
with select () or poll ().

Of course doing chroot add a very nice level of security.

-- 
au revoir, alain
----
Aussi haut que l'on soit assis, on n'est toujours assis que sur son cul !!!

---

From: Michael Douglass <[email-masked]>
Date: Tue, 16 Dec 1997 11:00:53 -0600

> Of course doing chroot add a very nice level of security.

Can you chroot() just a single thread?  That is the limitation.  The
chroot() would take affect for the entire process--it would suck if
all of a sudden only the first person to connect could do anything
at all. :(

-- 
Michael Douglass
Texas Networking, Inc.

<tnet admin> anyway, I'm off, perl code is making me [a] crosseyed toady

---

From: Alain Magloire <[email-masked]>
Date: Tue, 16 Dec 1997 13:01:56 -0500 (EST)

Bonjour M. Michael Douglass

> Can you chroot() just a single thread?  That is the limitation.

right, threads share the same address space.

> The chroot() would take affect for the entire process--it would suck if

I see you were talking about a _stand alone_ ftpd, I was not.

For a purely anonymous ftpd I can see this scheme:

	socket ();
	bind ();
	listen ();
	chdir ()/chroot ();
	while (1)
	{
		accept ();
		thread_create ();
	}

Of course the problem like you pointed is if you have a stand alone ftpd
the chroot () will affect the parent unless you fork (). But if
you have a non-forking or a threaded server, you want to avoid forking, right ?

IMO, For stand_alone servers using, non_forking or threads, the chroot ()
is close to useless or the code will be unacceptably complex.

of course 0.02 $ (with Canadian devaluation :)

---

From: Mike Hedlund <[email-masked]>
Date: Tue, 16 Dec 1997 11:46:28 -0800 (PST)

> you have a non-forking or a threaded server, you want to avoid forking, 

Yes.. the whole reason i wrote my own was because with > 2k concurrent
sessions (not even dataxfers) the machine (an ultra 2 with 2 cpus 256mb
ram and 1GB swap) would croak. Because each session == 1 process with
fork().

> IMO, For stand_alone servers using, non_forking or threads, the chroot()

Yupe.. i had to code in my own directory security. ie; since i have state
info for all connections i can keep their current directory, or what their
'root' directory should be. then rewrite it accordingly.. kinda like a web
server..

Also, a message before noted that with thread() and > around 700 sessions
would also kill the machine.. but thats assuming that you thread() the
accept and the whole session.. i went with a different algorithm. So that
X threads may do X sessions OR downloads.. since the only major blocking
is the sending/receiveing of the file.

-mike

---

From: Philip Gwyn <[email-masked]>
Date: Thu, 18 Dec 1997 17:53:20 -0500

At 01:01 PM 12/16/97 -0500, Alain Magloire wrote:
>> The chroot() would take affect for the entire process--it would 
>> suck if all of a sudden only the first person to connect could 
>> do anything at all. :(
>
>Of course the problem like you pointed is if you have a stand 
>alone ftpd the chroot () will affect the parent unless you fork 
>(). But if you have a non-forking or a threaded server, you want 
>to avoid forking, right ?

Or a hybrid?  Keep a pool of forked processes for each chroot(), then
create a new thread in the appropriate fork for each session.  The forked
processes would have to be expired at some point (time or number of
connections) to keep them clean and keep the number processes down.  

This way we limit the number of processes (only one per chroot).  And if
the number of threads in a process goes above a limit, then we create an
new process for the same chroot.

(Am I making sense?)

Example:
Start: main process for accept
Connection for 'fil': create PID 123=>'/', create thread in PID 123
Connection for 'anonymous': create PID 124=>'/home/ftp', create     thread
in PID 124
Connection for 'billy' (guest): create PID 1002=>'home/billy', create
thread in PID 1002
Connection for 'anonymous': create thread in PID 124
'fil' closed, keep PID 123
'billy' closed, expire process PID 1002
'anonymous' closed, keep PID 124

Or as psuedo-code:

while(1)
{
     S=accept();
     login=get_login_info(S)
     root=find_root(login);
     process=get_process(root);
     if(not process)
         process=create_process(root);
     create_thread(process, S, login);
}

get_process(root)
{
    for each PID in (process_list)
        if(PID->root == root and PID->usable)
            return PID;
    return NULL;
}

create_process(root)
{
    if(pid=fork)
    {
         add pid to process_list;
         return pid;
    } else
    { 
        chroot(root);   
        while(1)
        {
            wait4connection();
            split_thread();/* this reduces thread count when done */
            if(connection++>MAX_CONNECTION)
                exit(0);
        }        	
    }
}

create_thread(PID, connection, login)
{
    PID->threads++;
    jump_to_process();
    if(PID->threads > MAX_THREADS)
        PID->usable=0;
}

(Note: I'm glossing over the difficulties of inter-process and inter-thread
communication and the reaping of child processes.)