Hi, Here are some notes for you to write authentication module for openwebmail. We assume the module you want to write is auth_XYZ ps: A simplest way is to modify an existing one to fit your requirement. filename --------- The file name should be auth_XYZ.pl, XYZ could be A-Za-z and _ location -------- This auth_XYZ.pl should be put at the same directory as other auth module is. package name ------------ The package name for this module is ow::auth_XYZ The first line of auth_XYZ.pl should be package ow::auth_XYZ; functions ---------- An auth module should have the following 4 API routines get_userlist get_userinfo check_userpassword change_userpassword All functions follow this form ($retcode, $errmsg, retvals...)=routine($r_config, parameters); where: $retcode: 0 means ok, else means error $errmsg: message for sysadm, it will be logged to openwebmail.log this won't be displayed to user $r_config: reference of the system config hash %config # 0 : ok # -2 : parameter format error # -3 : authentication system/internal error # -4 : user doesn't exist ($retcode, $errmsg, realname, uid, gid, homedir)=get_userinfo($r_config, $user); # 0 : ok # -1 : function not supported # -3 : authentication system/internal error ($retcode, $errmsg,$userlist)=get_userlist($r_config); # 0 : ok # -2 : parameter format error # -3 : authentication system/internal error # -4 : password incorrect ($retcode, $errmsg)=check_userpassword($r_config, $user, $password) # 0 : ok # -1 : function not supported # -2 : parameter format error # -3 : authentication system/internal error # -4 : password incorrect ($retcode, $errmsg)=change_userpassword($r_config, $user, $oldpassword, $newpassword) conf file --------- you may read some config values from auth_XYZ.conf. Here is an example: If you have the following lines in auth_XYZ.conf option1 XXX option2 YYY option3 ZZZ Then you may put the following at the start of your auth module. ---------------------------------------------------- require "modules/tool.pl"; my %conf; if (($_=ow::tool::find_configfile('auth/auth_XYZ.conf')) ne '') { my ($ret, $err)=ow::tool::load_configfile($_, \%conf); die $err if ($ret<0); } ---------------------------------------------------- Then option values in conf file can be derived by $conf{'option1'}, $conf{'option2'}, $conf{'option3'} globals --------- Openwebmail can run in persistent mode, so you have to be very careful about the global variables. 1. only use 'my variable' for constant globals. If the global variable will be changed and referenced at runtime by routines, you need to delcare it with 'use vars qw(variable);' ps: this is due to the closure effect in persistent mode perl. Once a my variable is referenced by a sub routine, then the subroutine will has its own copy of this my variable. Then further change in the global my variable won't be seen by the subroutine. 2. code outside routines will be executed only once (when the module is required by main program) So the outside routine code should be used for init only 3. if you module has to chat with remote server, please do all the following thing in each of the 4 API routines open the connection, chat with server, close connection This is the simplest way, and it can avoid the problem of lost connection or server rebooting. Openwebmail will cache the userinfo for each session. In most case, each user session will need send only one request to auth server. 4. If you really need global variables, use 'use vars qw(variable)'. And please remember that value of global variables will be kept forever when running in persistent mode 5. if you hope to keep some connections to your remote server: a. you can use global variable to store connection handle but please don't do thing outside routines. b. all of the API routines should have the capability 1. if the connection has not been initialized => initialize the connection handle 2. if the connection is lost or dead => free old/stale connection handle reinitialize the connection handle 6. The signal handler for child process $SIG{CHLD} may have been set before calling the API routines, if your routine will fork new process, you may need to disable the handler temporarily by putting the following line in the routine local $SIG{CHLD}; undef $SIG{CHLD} More about persistent CGI ------------------------- 1. a persistent CGI process serves one request at a time, if more than one request come, more processes are forked 2. a persistent CGI process won't end after a request is completed, it waits for a new request and the global variable will be kept across requests. 3. Normally, a persistent perl CGI runs under main:: package Just the same as pure CGI 4. But SpeedyCGI has a group mode which puts servers CGIs into one process, each CGI is running under a package other than main::, And here are the differences in group mode: a. one resident perl process can be used to wait requests for different CGIs b. you can not access variable with prefix like $main:: or $::. c. Different CGI may share one copy of packages during differnt time So if package use global vraible to store state, the global may be changed or used by different CGIs