Developers' notes for tpop3d $Id: HACKING,v 1.11 2002/11/13 23:31:43 chris Exp $ tpop3d is designed with the development of new authentication schemes and mailbox drivers in mind. * Architecture tpop3d is a daemon server which forks children to handle incoming connections. All authentication and book-keeping is done by the main server process, which runs as root; all access to mailboxes is done by child processes, which drop privileges before opening the mailboxes. When an incoming connection needs to be authenticated, its credentials are passed to all available authentication drivers in turn, until either one authenticates it (perhaps also setting the location of the mailbox to use), or all drivers have been tried, in which case the attempt has failed. * Developing new authentication schemes The authentication strategy in tpop3d is very simple; a number of `authentication drivers' are defined, and referenced from authswitch.c. Individual requests for authentication (by USER/PASS or APOP) are passed to each in turn, and the first to return a positive response is considered to have successfully authenticated the user; no others are called. An example authentication driver, which uses getpwnam(3) and crypt(3) to perform `traditional' UNIX user authentication, is included in auth_passwd.[ch] (but is not, by default, included in the compiled binary). This driver is suitable for production use, but you are recommended to use PAM if your system supports it. auth_mysql.[ch] gives an example of an authentication driver for virtual domains. If you add a new authentication driver, it will probably have configuration options; tpop3d now warns about the presence of unknown configuration directives, and discards them. You will need to add your new directives to cfgdirectives.c. (I hope to make this process automatic, but have not quite decided which ugly C-preprocessor incantation to use. Note that the problem is not quite as trivial as grepping for `stringmap_find', since the set of valid directives changes based on various macro definitions.) Virtual domains are supported via users logging in with names such as `user@example.com'. The server supports adding `@example.com' based on the address to which a user connects. This is controlled via the append-domain configuration option (see the manual page for more information). Single- and multiple-IP virtual domain hosting can therefore be operated from a single server. The auth_other driver is designed to allow the painless development of new authentication strategies. In particular, it makes it easy to use programs written in a scripting language to do authentication; if you want to use this, have a look at the description in the man page and the example scripts in the scripts/ subdirectory. There is a perl module, which makes writing perl authenticators very easy, in the TPOP3D-AuthDriver subdirectory; the standard perl Makefile.PL ; make ; make install procedure will install it for you. The dotapopfile example perl script in scripts/ uses this module. If you wish to write an authenticator in perl, you can also use the auth_perl driver, which embeds a perl interpreter in the main tpop3d daemon. This may well be more efficient than using auth_other. * Developing new mailbox formats Mailbox drivers have a similar structure to authentication drivers; the code in maildir.c (contributed by Paul Makepeace) is a good initial place to start; the BSD mailspool code (mailspool.c) is complicated by the file locking muddle and by the mmap(2) code used to make it fast. * Future directions Things which are currently under consideration are listed in the TODO file in the distribution. * Coding style (Obviously you are free to write code however you want; this is a description of how I have formatted and structured the code in tpop3d.) Indentation is much like K&R, except that functions should look like this: int foo(char *bar) { /* ... */ } Functions should be commented like this: /* foo BAR * Calculate the foo value of the passed string BAR. The arguments and * return value of the function should be explained here, unless they are * blindingly obvious. */ int foo (const char *bar) { /* ... */ } Function names have lowercase words separated by underscores. The convention is that strings and other things returned by reference are allocated with xmalloc in the called function, and it is the caller's responsibility to xfree them. For more complex objects, there should be a constructor foo_new or foo_new_somehow, and a destructor foo_delete; methods on the object should be foo_this and foo_that. The exception to this is the list of message offsets and unique IDs in the mailbox object, which are now allocated in contiguous memory for performance reasons. Indentation is four spaces. Tabs should not, under any circumstances, appear in code.