Subject: Re: Securing Anonymous FTP Uploads
To: Curt Sampson <cjs@portal.ca>
From: Johan Danielsson <joda@pdc.kth.se>
List: tech-security
Date: 03/28/1997 23:38:11
Curt Sampson <cjs@portal.ca> writes:

> The following is a set of diffs I'm proposing to apply to our FTP
> daemon in order to make anonymous uploads more secure (i.e., less
> open to abuse).

We've already done this in an ftpd that was once taken from NetBSD.

> * Sets the default umask for anonymous users to 707, thus clearing
>   out all but group read/write/execute access on uploaded files.

We used 777, with an `-u' option to change it.

> * Disables the umask, chmod, delete and rmdir commands for anonymous
>   users.

Yes, and mkdir should not be disabled. It makes it a lot easier if
R. Luser can put his gazillion different files in one directory.

Furthermore, anonymous users has restrictions on the filenames they
may create.  This way you get rid of all the `...  warez ' files. For
instance:

void
makedir(char *name)
{

	LOGCMD("mkdir", name);
	if(guest && filename_check(name))
	    return;
	if (mkdir(name, 0777) < 0)
		perror_reply(550, name);
	else{
	    if(guest)
		chmod(name, 0700); /* guest has umask 777 */
	    reply(257, "MKD command successful.");
	}
}

and:

int 
filename_check(char *filename)
{
    static const char good_chars[] = "+-=_,.";
    char *p;

    p = strrchr(filename, '/');
    if(p)
	filename = p + 1;

    p = filename;

    if(isalnum(*p)){
	p++;
	while(*p && (isalnum(*p) || strchr(good_chars, *p)))
	    p++;
	if(*p == '\0')
	    return 0;
    }
    lreply(553, "\"%s\" is an illegal filename.", filename);
    lreply(553, "The filename must start with an alphanumeric "
	   "character and must only");
    reply(553, "consist of alphanumeric characters or any of the following: %s", 
	  good_chars);
    return 1;
}

>  	| DELE check_login SP pathname CRLF
>  		{
> -			if ($2 && $4 != NULL)
> -				delete($4);
> -			if ($4 != NULL)
> -				free($4);
> +			if (guest)  {
> +			    reply(502,
> +			        "Anonymous users may not use this command.");
> +			} else {
> +			    if ($2 && $4 != NULL)
> +				    delete($4);
> +			    if ($4 != NULL)
> +				    free($4);
> +			}

I thought is was more elegant to add an `check_login_no_guest' and
just change the relevant commands.

/Johan