This article is from the Anonymous FTP FAQ, by Christopher Klaus cklaus@iss.net with numerous contributions by others.
1. Create the user ftp in /etc/passwd. Use a misc group. The user's home directory will be ~ftp where ~ftp is the root you wish anonymous users to see. Creating this user turns on anonymous ftp.
Use an invalid password and user shell for better security. The entry in the passwd file should look something like:
ftp:*:400:400:Anonymous FTP:/home/ftp:/bin/true
2. Create the home directory ~ftp. Make the directory owned by root (NOT ftp) with the same group as ftp. Thus, owner permissions are for root and group permissions are for the anonymous users. Set the permissions for ~ftp to 555 (read, nowrite, execute).
Warning: Some MAN pages recommend making the ~ftp directory owned by ftp. This is a big NO-NO, if you want any type of security on your system.
3. Create the directory ~ftp/bin. This directory is owned by root (group e.g. wheel) with permissions 111 (noread, nowrite, execute).
4. Copy the program ls into ~ftp/bin. ls is owned by root with permissions 111 (noread, nowrite, execute). Any other commands you put in ~ftp/bin should have the same permissions as well.
5. Make the directory ~ftp/etc. This directory is owned by root with permissions 111.
6. Create from scratch the files /etc/passwd and /etc/group in ~ftp/etc. These files should be mode 444. The passwd file should only contain root, daemon, uucp, and ftp. The group file must contain ftp's group. Use your /etc/passwd and /etc/group files as a template for creating passwd and group files going to ~ftp/etc. You may even change the user names in this file, they are used only for 'ls' command. So for example if all files in your ~ftp/pub/linux hierarchy will be maintained by a real user 'balon' with uid=156 you may put
linux:*:156:120:Kazik Balon::
in the ~ftp/etc/passwd file (regardless of his real username). Leave only these users who will own files under ftp hierarchy (e.g. root, daemon, ftp...) and definitely remove *ALL* passwords by replacing them with '*' so the entry looks like:
root:*:0:0:Ftp maintainer::
ftp:*:400:400: Anonymous ftp::
For more security, you can just remove ~ftp/etc/passwd and ~ftp/etc/group (the effect is that ls -l will not show the directories' group names). Wuarchive ftp daemon (and some others) have some extensions based on the contents of the group/passwd files, so read the appropriate documentation.
7. Make the directory ~ftp/pub. This directory is owned by you and has the same group as ftp with permissions 555. On most systems (like SunOS) you may want to make this directory 2555, ie. set-group-id, in order to create new files with the same group ownership.
Files are left here for public distribution. All folders inside ~ftp/pub should have the same permissions as 555.
Warning: Neither the home directory (~ftp) nor any directory below it should be owned by ftp! No files should be owned by ftp either. Modern ftp daemons support all kinds of useful commands, such as chmod, that allow outsiders to undo your careful permission settings. They also have configuration options like the following (WuFTP) to disable them:
# all the following default to "yes" for everybody delete no guest,anonymous # delete permission? overwrite no guest,anonymous # overwrite permission? rename no guest,anonymous # rename permission? chmod no anonymous # chmod permission? umask no anonymous # umask permission?
# specify the upload directory information upload /var/spool/ftp * no upload /var/spool/ftp /incoming yes ftp staff 0600 nodirs # path filters # path-filter... path-filter anonymous /etc/msgs/pathmsg ^[-A-Za-z0-9_\.]*$ ^\. ^- path-filter guest /etc/msgs/pathmsg ^[-A-Za-z0-9_\.]*$ ^\. ^-
#strip prefix:strip postfix:addon prefix:addon postfix:external command: #types:options:description :.Z: : :/bin/compress -d -c %s:T_REG|T_ASCII:O_UNCOMPRESS:UNCOMPRESS :-z: : :/bin/compress -d -c %s:T_REG|T_ASCII:O_UNCOMPRESS:UNCOMPRESS : : :.Z:/bin/compress -c %s:T_REG:O_COMPRESS:COMPRESS : : :.tar:/bin/tar cf - %s:T_REG|T_DIR:O_TAR:TAR : : :.tar.Z:/bin/pipe /bin/tar cf - %s | /bin/compress -c:T_REG|T_DIR:O_COMPRESS|O_TAR:TAR+COMPRESS : : :.tar:/bin/gtar -c -f - %s:T_REG|T_DIR:O_TAR:TAR : : :.tar.Z:/bin/gtar -c -Z -f - %s:T_REG|T_DIR:O_COMPRESS|O_TAR:TAR+COMPRESS : : :.tar.gz:/bin/gtar -c -z -f - %s:T_REG|T_DIR:O_COMPRESS|O_TAR:TAR+GZIP
-----------------8<-------------cut--------------- /* pipe.c: exec two commands in a pipe */ #define NULL (char *)0 #define MAXA 16 main(argc, argv) int argc; char *argv[]; { char *av1[MAXA], *av2[MAXA]; int i, n, p[2], cpid; i = 0; n = 0; while ( ++i < argc && n < MAXA ) { if ( *argv[i] == '|' && *(argv[i]+1) == '\0' ) break; av1[n++] = argv[i]; } if ( n == 0 ) uexit(); av1[n] = NULL; n = 0; while ( ++i < argc && n < MAXA ) av2[n++] = argv[i]; if ( n == 0 ) uexit(); av2[n] = NULL; if ( pipe(p) != 0 ) exit(1); if ( ( cpid = fork() ) == (-1) ) exit(1); else if ( cpid == 0 ) { (void)close(p[0]); (void)close(1); (void)dup(p[1]); (void)close(p[1]); (void)execv(av1[0], av1); _exit(127); } else { (void)close(p[1]); (void)close(0); (void)dup(p[0]); (void)close(p[0]); (void)execv(av2[0], av2); _exit(127); } /*NOTREACHED*/ } uexit() { (void)write(2, "Usage: pipe | \n", 34); exit(1); } -------- CUT HERE ------------
 
Continue to: