diff -ruN qpopper4.0.3/README.MYSQL qpopper4.0.3-mysql-0.4/README.MYSQL --- qpopper4.0.3/README.MYSQL Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/README.MYSQL Thu Apr 4 15:07:14 2002 @@ -0,0 +1,172 @@ +This is a quick readme for my mysql support in Qpopper 4.0.3 (-mysql-0.4) + +Sample mysql config directives are stored in the mysql-popper.conf +file in the main directory. + +Configure directives relative to mysql support are: + --with-mysqllibpath=path + Set the mysql library path [/usr/local/mysql/lib/mysql] + --with-mysqlincludepath=path + Set the mysql include path [/usr/local/mysql/include/mysql] + --enable-mysql + compile in mysql authentication + --with-mysqlconfig=path + Set the mysql-popper.conf file path [/etc/mysql-popper.conf] + --enable-log-login-mysql + Log successful user authentications into mysql database + + +For --enable-log-login-mysql, currently the table and field definitions +are hardcoded. It is defined in mysql as follows where ip is the client IP +and ts is the current timestamp in unix time: + +CREATE TABLE relays ( + ip char(15) NOT NULL default '', + ts int(11) NOT NULL default '0', + KEY ip(ip) +); + +The authentication table should look something like this: +The only REQUIRED fields are username and password. +In a virtual domain setup, the username field should contain +ONLY the username, not username@userdomain.com. userdomain.com +goes in the domain field. +The password field can contain many types of encoded passwords. +The supported types are: +cleartext (just plain text in mysql), +crypt (made with ENCRYPT('userpassword') in mysql), +md5 (made with MD5('userpassword') in mysql), and +mysql (made with PASSWORD('userpassword') in mysql). + +The other fields you only need to create if you query for said fields in +your mysql-popper.conf configuration. + +CREATE TABLE email ( + username char(128) NOT NULL, + domain char(64) NOT NULL, + uid int(10) NOT NULL, + gid int(10) NOT NULL, + status int(2) DEFAULT '0' NOT NULL, + shell char(127) NOT NULL, + password char(32) NOT NULL +); + +How to populate the auth. table with users is beyond the scope of this +document. Reference your MySQL docs for the SQL commands to do this. +But here's a quick example for an email of thelittleprince@asteroid-b612.org: + INSERT into email VALUES ( + 'thelittleprince', + 'asteroid-b612.org', + '500', + '100', + '1', + '/bin/false', + ENCRYPT('mypassword') + ); + + +DIRECTORY STRUCTURES (PLEASE READ!): +When you use mysql, either with virtual or non-virtual set ups, +spool directory or HOMEDIRMAIL set ups, some of the directory +paths are constructed differently. Here is a run-down of how paths +are constructed with this patch: +In these examples POP_DROP_DIR is represented as /var/tmp/.pop +POP_CACHE_DIR as /var/tmp/.cache +POP_MAILDIR as /var/spool/mail +and MYSQL_DEFAULT_HOMEDIR as /home + +NON-VIRTUAL (i.e. USER user) + POP_MAILDIR SETUP: + GNPH_PATH : /var/spool/mail + GNPH_PATH (HASHED): /var/spool/mail/u/s + GNPH_SPOOL : /var/spool/mail/user + GNPH_SPOOL (HASHED): /var/spool/mail/u/s/user + GNPH_OLDPOP : /var/spool/mail/.user.pop + GNPH_OLDPOP (HASHED): /var/spool/mail/u/s/.user.pop + GNPH_POP : /var/tmp/.pop/.user.pop + GNPH_POP (HASHED): /var/tmp/.pop/u/s/.user.pop + GNPH_CACHE : /var/tmp/.cache/.user.cache + GNPH_CACHE (HASHED): /var/tmp/.cache/u/s/.user.cache + HOMEDIRMAIL SETUP: + GNPH_PATH : /home/user + GNPH_PATH (HASHED): /home/u/s/user + GNPH_SPOOL : /home/user/mbox + GNPH_SPOOL (HASHED): /home/u/s/user/mbox + GNPH_OLDPOP : /var/spool/mail/.user.pop + GNPH_OLDPOP (HASHED): /var/spool/mail/u/s/.user.pop + GNPH_POP : /var/tmp/.pop/.user.pop + GNPH_POP (HASHED): /var/tmp/.pop/u/s/.user.pop + GNPH_CACHE : /var/tmp/.cache/.user.cache + GNPH_CACHE (HASHED): /var/tmp/.cache/u/s/.user.cache +VIRTUAL SETUP (i.e. USER user@domain.com) + POP_MAILDIR SETUP: + GNPH_PATH : /var/spool/mail/domain.com + GNPH_PATH (HASHED): /var/spool/mail/domain.com/u/s + GNPH_SPOOL : /var/spool/mail/domain.com/user + GNPH_SPOOL (HASHED): /var/spool/mail/domain.com/u/s/user + GNPH_OLDPOP : /var/spool/mail/domain.com/.user.pop + GNPH_OLDPOP (HASHED): /var/spool/mail/domain.com/u/s/.user.pop + GNPH_POP : /var/tmp/.pop/.user@domain.com.pop + GNPH_POP (HASHED): /var/tmp/.pop/u/s/.user@domain.com.pop + GNPH_CACHE : /var/tmp/.cache/.user@domain.com.cache + GNPH_CACHE (HASHED): /var/tmp/.cache/u/s/.user@domain.com.cache + HOMEDIRMAIL SETUP: + GNPH_PATH : /home/domain.com/user + GNPH_PATH (HASHED): /home/domain.com/u/s/user + GNPH_SPOOL : /home/domain.com/user/mbox + GNPH_SPOOL (HASHED): /home/domain.com/u/s/user/mbox + GNPH_OLDPOP : /var/spool/mail/domain.com/.user.pop + GNPH_OLDPOP (HASHED): /var/spool/mail/domain.com/u/s/.user.pop + GNPH_POP : /var/tmp/.pop/.user@domain.com.pop + GNPH_POP (HASHED): /var/tmp/.pop/u/s/.user@domain.com.pop + GNPH_CACHE : /var/tmp/.cache/.user@domain.com.cache + GNPH_CACHE (HASHED): /var/tmp/.cache/u/s/.user@domain.com.cache + +USER CONFIG OPTIONS: + POP_MAILDIR SETUP: + NON-VIRTUAL: + /var/spool/mail/.user.qpopper-options + VIRTUAL: + /var/spool/mail/.user@domain.com.qpopper-options + HOMEDIRMAIL SETUP: + NON-VIRTUAL: + /home/user/.qpopper-options + /home/u/s/user/.qpopper-options + VIRTUAL: + /home/domain.com/user/.qpopper-options + /home/domain.com/u/s/user/.qpopper-options + +If you're using HOMEDIRMAIL, the DEFAULT_MYSQL_HOMEDIR variable +in pop_user.c controls the base home directory for users. The default +is "/home" + +HOW THE MYSQL AUTHENTICATION WORKS: +In pop_user() a mysql connection and query is made with the username +entered as the search field (and the user's domain in a virtual setup). +The resulting data is stored in the passwd structure that would normally +be populated by getpwnam(). +In pop_pass() the cached DB password in the passwd structure is compared +against the entered password, using whatever method is specified in the +MysqlAuthPasswordMethod config file option. +On success and enabling of log-login-mysql, an additional mysql connection +is made to the above table and appended/updated with the client's ip +and the current unix timestamp. + +EXTRA NOTES: +If using the log-login-mysql option in conjunction with your MTA for +host relay checking, i'm told this is the proper relay config for Exim: + +host_accept_relay = "localhost:mysql;SELECT ip FROM +relay_ip WHERE ip='${sender_host_address}'" + +or if you want to only select on ips less than 180 secs (3 min) old.. + +host_accept_relay = "localhost:mysql;SELECT ip FROM +relay_ip WHERE ip='${sender_host_address}' AND +((UNIX_TIMESTAMP() - 180) < ts)" + + + +-Tony +thelittleprince@asteroid-b612.org + diff -ruN qpopper4.0.3/config.h.in qpopper4.0.3-mysql-0.4/config.h.in --- qpopper4.0.3/config.h.in Tue Apr 3 17:23:08 2001 +++ qpopper4.0.3-mysql-0.4/config.h.in Mon Oct 29 13:54:24 2001 @@ -286,11 +286,25 @@ /* Define to enable SCRAM */ #undef SCRAM +/* Define to enable MYSQL_CONF */ +#undef MYSQL_CONF + /* Define the POPUID as pop user ID which acts as admin for POPUSERS */ #undef POPUID /* Define if you want successful authentications to be logged */ #undef LOG_LOGIN + +/* + * Use mysql database authentication + */ +#undef MYSQLAUTH + +/* + * Define if you want successful authentications to be + * logged to a mysql database + */ +#undef LOG_LOGIN_MYSQL /* * Define if you want to automatically delete RETRd messages. diff -ruN qpopper4.0.3/configure qpopper4.0.3-mysql-0.4/configure --- qpopper4.0.3/configure Tue Apr 3 17:28:30 2001 +++ qpopper4.0.3-mysql-0.4/configure Mon Oct 29 13:54:24 2001 @@ -24,6 +24,16 @@ ac_help="$ac_help --enable-low-debug Low-level heavy-duty debugging only." ac_help="$ac_help + --with-mysqllibpath=path Set the mysql library path [/usr/local/mysql/lib/mysql]" +ac_help="$ac_help + --with-mysqlincludepath=path Set the mysql include path [/usr/local/mysql/include/mysql]" +ac_help="$ac_help + --enable-mysql compile in mysql authentication" +ac_help="$ac_help + --with-mysqlconfig=path Set the mysql-popper.conf file path [/etc/mysql-popper.conf]" +ac_help="$ac_help + --enable-log-login-mysql Log successful user authentications into mysql database " +ac_help="$ac_help --enable-servermode Enable SERVER_MODE " ac_help="$ac_help --enable-bulletins=directory @@ -1490,6 +1500,168 @@ EOF CFLAGS=`echo "$CFLAGS" | sed 's/-O2//'` +fi + + +# Check whether --with-mysqllibpath or --without-mysqllibpath was given. +if test "${with_mysqllibpath+set}" = set; then + withval="$with_mysqllibpath" + mysqllibpath=$withval +else + mysqllibpath="/usr/local/mysql/lib/mysql" +fi + +# Check whether --with-mysqlincludepath or --without-mysqlincludepath was given. +if test "${with_mysqlincludepath+set}" = set; then + withval="$with_mysqlincludepath" + mysqlincludepath=$withval +else + mysqlincludepath="/usr/local/mysql/include/mysql" +fi + + +# Check whether --enable-mysql or --disable-mysql was given. +if test "${enable_mysql+set}" = set; then + enableval="$enable_mysql" + mysql="$enableval" +else + mysql="no" +fi + +if test "$mysql" != "no"; then + OS_DEFS="$OS_DEFS -I$mysqlincludepath" + LDFLAGS="$LDFLAGS -L$mysqllibpath" + echo $ac_n "checking for mysql_connect in -lmysqlclient""... $ac_c" 1>&6 +echo "configure:1597: checking for mysql_connect in -lmysqlclient" >&5 +ac_lib_var=`echo mysqlclient'_'mysql_connect | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lmysqlclient "-lm" $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -L$mysqllibpath -lmysqlclient" +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: "libmysqlclient not found"" 1>&2; exit 1; } +fi + + echo $ac_n "checking for sin in -lm""... $ac_c" 1>&6 +echo "configure:1638: checking for sin in -lm" >&5 +ac_lib_var=`echo m'_'sin | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + echo "$ac_t""Turning on mysql authentication" 1>&6 + cat >> confdefs.h <<\EOF +#define MYSQLAUTH 1 +EOF + +fi + +# Check whether --with-mysqlconfig or --without-mysqlconfig was given. +if test "${with_mysqlconfig+set}" = set; then + withval="$with_mysqlconfig" + mysqlconfig=$withval +else + mysqlconfig="no" +fi + +if test "$mysqlconfig" != "no"; then + cat >> confdefs.h <> confdefs.h <&6 + cat >> confdefs.h <<\EOF +#define LOG_LOGIN_MYSQL 1 +EOF + fi diff -ruN qpopper4.0.3/configure.in qpopper4.0.3-mysql-0.4/configure.in --- qpopper4.0.3/configure.in Tue Apr 3 17:23:08 2001 +++ qpopper4.0.3-mysql-0.4/configure.in Mon Oct 29 13:54:24 2001 @@ -364,6 +364,38 @@ fi +AC_ARG_WITH(mysqllibpath, [ --with-mysqllibpath=path Set the mysql library path [/usr/local/mysql/lib/mysql]], mysqllibpath=$withval, mysqllibpath="/usr/local/mysql/lib/mysql") +AC_ARG_WITH(mysqlincludepath, [ --with-mysqlincludepath=path Set the mysql include path [/usr/local/mysql/include/mysql]], mysqllibpath=$withval, mysqllibpath="/usr/local/mysql/include/mysql") + +AC_ARG_ENABLE(mysql, [ --enable-mysql compile in mysql authentication], + mysql="$enableval", mysql="no") +if test "$mysql" != "no"; then + OS_DEFS="$OS_DEFS -I$mysqlincludepath" + LDFLAGS="$LDFLAGS -L$mysqllibpath" + AC_CHECK_LIB(mysqlclient, mysql_connect, + LIBS="$LIBS -L$mysqllibpath -lmysqlclient", + AC_MSG_ERROR("libmysqlclient not found"),"-lm") + AC_CHECK_LIB(m, sin) + AC_MSG_RESULT(Turning on mysql authentication) + AC_DEFINE(MYSQLAUTH) +fi + +AC_ARG_WITH(mysqlconfig, [ --with-mysqlconfig=path Set the mysql-popper.conf file path [/etc/mysql-popper.conf]], mysqlconfig=$withval, mysqlconfig="no") +if test "$mysqlconfig" != "no"; then + AC_DEFINE_UNQUOTED(MYSQL_CONF,"$mysqlconfig") +else + AC_DEFINE_UNQUOTED(MYSQL_CONF,"/etc/mysql-popper.conf") +fi + + +AC_ARG_ENABLE(log-login-mysql, [ --enable-log-login-mysql Log successful user authentications into mysql database ], + logloginmysqlmode="$enableval", logloginmysqlmode="no") +if test "$logloginmysqlmode" != "no"; then + AC_MSG_RESULT(Enabled LOG-LOGIN-MYSQL) + AC_DEFINE(LOG_LOGIN_MYSQL) +fi + + AC_ARG_ENABLE(servermode, [ --enable-servermode Enable SERVER_MODE ], servermode="$enableval", servermode="no") if test "$servermode" != "no"; then diff -ruN qpopper4.0.3/doc/Changes.MYSQL qpopper4.0.3-mysql-0.4/doc/Changes.MYSQL --- qpopper4.0.3/doc/Changes.MYSQL Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/doc/Changes.MYSQL Thu Apr 4 15:16:52 2002 @@ -0,0 +1,38 @@ + Last updated: 4 April 2002 + +Changes from 0.3 to 0.4: +--------------------------- + 1. Added ability to do HOMEDIRMAIL with mysql authentication. + "/home" is the default base path for the user's home directory + (since we're not using /etc/passwd). + You can change this by modifying MYSQL_DEFAULT_HOMEDIR in pop_user.c + You can use this with a virtual setup and hashing. + Example directory paths are /home/user, /home/u/s/user, /home/domain.com/ + user, /home/domain.com/u/s/user (see README.MYSQL for all of them) + 2. Changed error message for bad sql fetch to say "Authentication query + failed, account may not exist." instead of saying that the password for + that account is incorrect. + 3. Added "md5" and "mysql" methods for password checking + (for the MysqlAuthPasswordMethod option). Also added "any" method which + will check all methods (since now there are more than 2). The "both" + method can still be used. I left it in for compatibility. + 4. Added hashing and virtual cases for user-opt/spool-opt paths + in pop_config.c + 5. Updated README.MYSQL + +Changes from 0.2 to 0.3: +--------------------------- + 1. Fixed glitch in pop_user.c, where string copied to p->user for MYSQLAUTH + contained domain name, when it shouldn't have. + 2. Fixed compile problem in genpath.c, when qpopper not compiled with + MYSQLAUTH + +Changes from 0.1 to 0.2: +--------------------------- + 1. Added debugging calls for mysql auth. + 2. Added config variables MysqlAuthDomainField and MysqlAuthDefaultDomain + to mysql-popper.conf + 3. Added pre-release virtual domain support. + 4. Updated README.MYSQL + 5. Created Changes.MYSQL + diff -ruN qpopper4.0.3/doc/Changes.MYSQL.save qpopper4.0.3-mysql-0.4/doc/Changes.MYSQL.save --- qpopper4.0.3/doc/Changes.MYSQL.save Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/doc/Changes.MYSQL.save Thu Mar 7 17:59:54 2002 @@ -0,0 +1,37 @@ + Last updated: 7 March 2002 + +Changes from 0.3 to 0.4: +--------------------------- + 1. Added ability to do HOMEDIR mail with mysql authentication. + "/home" is the default base path for the user's home directory + (since we're not using /etc/passwd). + You can change this by modifying MYSQL_DEFAULT_HOMEDIR in pop_user.c + You can user this with a virtual setup and hashing. + Example directory paths are /home/user, /home/u/s/user, /home/domain.com/ + user, /home/domain.com/u/s/user (see README.MYSQL for all of them) + 2. Changed error message for bad sql fetch to say "Authentication query + failed, account may not exist." instead of saying that the password for + that account is incorrect. + 3. Added "md5" and "mysql" methods for password checking + (for the MysqlAuthPasswordMethod option). Also added "any" method which + will check all methods (since now there are more than 2). The "both" + method can still be used. I left it in for compatibility. + 4. Updat + 4. Updated README.MYSQL + +Changes from 0.2 to 0.3: +--------------------------- + 1. Fixed glitch in pop_user.c, where string copied to p->user for MYSQLAUTH + contained domain name, when it shouldn't have. + 2. Fixed compile problem in genpath.c, when qpopper not compiled with + MYSQLAUTH + +Changes from 0.1 to 0.2: +--------------------------- + 1. Added debugging calls for mysql auth. + 2. Added config variables MysqlAuthDomainField and MysqlAuthDefaultDomain + to mysql-popper.conf + 3. Added pre-release virtual domain support. + 4. Updated README.MYSQL + 5. Created Changes.MYSQL + diff -ruN qpopper4.0.3/example-mysql-configure.txt qpopper4.0.3-mysql-0.4/example-mysql-configure.txt --- qpopper4.0.3/example-mysql-configure.txt Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/example-mysql-configure.txt Mon Oct 29 13:54:24 2001 @@ -0,0 +1 @@ +./configure --enable-servermode --enable-shy --enable-specialauth --enable-temp-drop-dir=/var/spool/mail/.pop --disable-check-pw-max --enable-fast-update --prefix=/usr --disable-hash-dir-check --enable-standalone --enable-mysql --enable-log-login-mysql --with-mysqlconfig=/etc/mysql-popper.conf diff -ruN qpopper4.0.3/mysql-popper.conf qpopper4.0.3-mysql-0.4/mysql-popper.conf --- qpopper4.0.3/mysql-popper.conf Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/mysql-popper.conf Thu Mar 7 15:05:18 2002 @@ -0,0 +1,93 @@ +# Host where Mysql server is. Defaults to "localhost" +MysqlAuthHost xxx.xxx.xxx.xxx + +# Port on which Mysql daemon runs. Defaults to "3306" +MysqlAuthPort 3306 + +# Database to auth off. Defaults to "authdb" +MysqlAuthDb authdb + +# Username and password used to connect to Mysql daemon +# REQUIRED +MysqlUsername root +MysqlPassword mypassword +# aliases for the above +#MysqlAuthUsername root +#MysqlAuthPassword mypassword + +# The table we auth off of +# Defaults to "qpopper" +MysqlAuthTable email + +# The method we will use to compare the user-entered +# password against their database password +# "cleartext" if your db passwords are in cleartext +# "crypt" if your db passwords are unix crypted +# "md5" if your db passwords are MD5() encoded +# "mysql" if your db passwords are PASSWORD() encoded (MySQL's method) +# "both" to check both cleartext and crypt +# "any" to check all methods +# Defaults to "cleartext" +MysqlAuthPasswordMethod cleartext + +# Field where user username is +# Defaults to "username" +MysqlAuthUsernameField username + +# VIRTUAL DOMAIN SETUP +# In a virtual setup, the mail spool DIRECTORY will be constructed +# by using the POP_MAILDIR variable + the user's domain +# e.g. /var/spool/mail/yourdomain.com/ +# If hashing is enabled, it is done AFTER this is constructed. +# e.g. for a hash setting of 2, /var/spool/mail/yourdomain.com/u/s/ +# (for a username of "user") +# If using HOMEDIRMAIL, refer to the path structures explained +# in the README.MYSQL +# +# YOU MUST DEFINE *BOTH* OF THE FOLLOWING 2 DOMAIN OPTIONS +# IN A VIRUTAL DOMAIN SETUP. +# +# Field where user domain is +# Define this for a virtual domain setup +# DONT define it for a non-virtual domain setup +#MysqlAuthDomainField domain +# +# If you defined MysqlAuthDomainField and a user does not +# specify a domain in his username, i.e. "USER username" +# this will get used as the default domain..so it will be as +# if he did "USER username@yourdomain.com" +#MysqlAuthDefaultDomain yourdomain.com +# +# END VIRTUAL DOMAIN SETUP + +# Field where user password is +# Defaults to "password" +MysqlAuthPasswordField password + +# Options to get user UID. +# REQUIRED - MUST specify/uncomment one +MysqlAuthUidField uid +#MysqlAuthUid 65534 +#MysqlAuthUidName nobody + +# Options to get user GID. +# REQUIRED - MUST specify/uncomment one +#MysqlAuthGidField gid +MysqlAuthGid 100 +#MysqlAuthGidName nobody + +# If defined, specifies a field to check for account status +# where when field value = 1, account is active. +# 0 is disabled, 2 is suspended, 3 is on-hold. +MysqlAuthAcctStatusField status + +# If defined, specifies a field to check for the user's shell. +# If not defined, default shell given to all users is /bin/false +#MysqlShellField shell + +# +# There is no config field for specifying the user's spool +# in the mysql table. +# + + diff -ruN qpopper4.0.3/popper/Makefile.in qpopper4.0.3-mysql-0.4/popper/Makefile.in --- qpopper4.0.3/popper/Makefile.in Sun Apr 22 15:59:15 2001 +++ qpopper4.0.3-mysql-0.4/popper/Makefile.in Mon Oct 29 13:54:24 2001 @@ -115,7 +115,7 @@ pop_extend.o scram.o hmac.o base64.o pop_util.o \ get_sub_opt.o msg_ptr.o drac.o pop_config.o pop_tls.o \ pop_tls_openssl.o pop_tls_sslplus.o sslplus_utils.o \ - main.o pop_cache.o genpath.o + main.o pop_cache.o genpath.o pop_conf.o SRCS = pop_dele.c pop_dropcopy.c \ pop_get_command.c pop_get_subcommand.c pop_init.c \ @@ -128,7 +128,7 @@ pop_extend.c scram.c hmac.c base64.c pop_util.c \ get_sub_opt.c msg_ptr.c drac.c pop_config.c pop_tls.c \ pop_tls_openssl.c pop_tls_sslplus.c sslplus_utils.c \ - main.c pop_cache.c genpath.c + main.c pop_cache.c genpath.c pop_conf.c POPAUTHOBJS = base64.o scram.o md5.o \ hmac.o popauth.o diff -ruN qpopper4.0.3/popper/genpath.c qpopper4.0.3-mysql-0.4/popper/genpath.c --- qpopper4.0.3/popper/genpath.c Sun May 6 18:00:49 2001 +++ qpopper4.0.3-mysql-0.4/popper/genpath.c Thu Mar 7 15:23:09 2002 @@ -103,9 +103,14 @@ genpath ( POP *p, char *pszDrop, int iDropLen, GNPH_WHICH iWhich ) { char *pszUser = NULL; /* user name */ + char *userdomain = NULL; /* user name and domain */ int len1 = 0; /* used with strlcpy/strlcat */ int len2 = 0; /* used with strlcat */ int len3 = 0; /* used with strlcat */ + int len4 = 0; /* used with strlcat */ + int len5 = 0; /* used with strlcat */ + int len6 = 0; /* used with strlcat */ + int len7 = 0; /* used with strlcat */ int iChunk = 0; /* used with Qsnprintf */ struct passwd *pw = &p->pw; @@ -157,6 +162,19 @@ DEBUG_LOG2 ( p, "...built: (%d) '%.100s'", len1 + len2, pszDrop ); +#ifdef MYSQLAUTH + /* we dont add the domain on the path when creating the temp_drop */ + /* we dont add the domain on the path when creating the cache */ + /* we will do user@mydomain.com.pop and user@mydomain.com.cache instead */ + if (iWhich != GNPH_POP && iWhich != GNPH_CACHE) { + if (strcmp(p->domain,"NULL")) { + len4 = strlcat ( pszDrop, p->domain, iDropLen ); + len5 = strlcat ( pszDrop, "/", iDropLen ); + DEBUG_LOG2 ( p, "...built: (%d) '%.100s'", len1 + len2, pszDrop ); + } + } /* iWhich */ +#endif + /* * Next, the hashed directory (if in use) */ @@ -164,13 +182,29 @@ len3 = strlcat ( pszDrop, get_hash_dir ( pszUser, p->hash_spool ), iDropLen ); DEBUG_LOG2 ( p, "...built: (%d) '%.100s'", - len1 + len2 + len3, pszDrop ); + len1 + len2 + len3 + len4 + len5, pszDrop ); + } + +#ifdef MYSQLAUTH + /* If we are doing mysql auth AND user is using HOMEDIRMAIL */ + /* then we have to put the username on the end here since pw_dir */ + /* only hold the base home directory, so domain and hashing can */ + /* be tacked on, if needed */ + if (p->pHome_dir_mail != NULL) { + if (iWhich == GNPH_PATH || iWhich == GNPH_SPOOL) { + len6 = strlcat ( pszDrop, p->user, iDropLen ); + len7 = strlcat ( pszDrop, "/", iDropLen ); + } } +#endif + /* * Check for truncation */ - if ( len1 > iDropLen || len2 > iDropLen || len3 > iDropLen ) { + if ( len1 > iDropLen || len2 > iDropLen || len3 > iDropLen || + len4 > iDropLen || len5 > iDropLen || len6 > iDropLen || + len7 > iDropLen) { pop_log ( p, POP_PRIORITY, HERE, @@ -194,9 +228,21 @@ break; case GNPH_POP: /* .pop file */ +#ifdef MYSQLAUTH + userdomain = (char *)malloc(strlen(pszUser)+strlen(p->domain)+2); + if (strcmp(p->domain,"NULL")) { + strcpy(userdomain,pszUser); + strcat(userdomain,"@"); + strcat(userdomain,p->domain); + } /* mysqlauth_domain_field */ + else strcpy(userdomain,pszUser); +#else + userdomain = (char *)malloc(strlen(pszUser)+2); + strcpy(userdomain,pszUser); +#endif iChunk = Qsprintf ( pszDrop + strlen(pszDrop), p->pCfg_temp_name, - pszUser ); + userdomain ); break; case GNPH_TMP: /* tmpxxxx */ @@ -216,9 +262,21 @@ break; case GNPH_CACHE: /* .cache file */ +#ifdef MYSQLAUTH + userdomain = (char *)malloc(strlen(pszUser)+strlen(p->domain)+2); + if (strcmp(p->domain,"NULL")) { + strcpy(userdomain,pszUser); + strcat(userdomain,"@"); + strcat(userdomain,p->domain); + } /* mysqlauth_domain_field */ + else strcpy(userdomain,pszUser); +#else + userdomain = (char *)malloc(strlen(pszUser)+2); + strcpy(userdomain,pszUser); +#endif iChunk = Qsprintf ( pszDrop + strlen(pszDrop), p->pCfg_cache_name, - pszUser ); + userdomain ); break; case GNPH_PATH: /* Just the path, M'am */ diff -ruN qpopper4.0.3/popper/pop_conf.c qpopper4.0.3-mysql-0.4/popper/pop_conf.c --- qpopper4.0.3/popper/pop_conf.c Wed Dec 31 16:00:00 1969 +++ qpopper4.0.3-mysql-0.4/popper/pop_conf.c Wed Mar 6 00:20:50 2002 @@ -0,0 +1,171 @@ +/* + * pop_conf.c - 06/20/2001 + * Anthony J. Biacco - thelittleprince@asteroid-b612.org + */ + + +#include "config.h" + +#ifdef MYSQLAUTH + +#include +#include +#include +#include +#include +#if HAVE_STRINGS_H +# include +#endif + +#include +#include +#include "popper.h" + +#define BUFSIZE 128 + +struct config_options { + char *name; + char **value; + char *default_value; +}; + + +char *mysqlauth_uid_name; +char *mysqlauth_gid_name; +char *mysqlauth_uid_s; +char *mysqlauth_gid_s; + +struct config_options options[] = { + /* Host user for authentication */ + {"mysqlauthhost", &mysqlauth_host, "localhost"}, + /* Mysql port */ + {"mysqlauthport", &mysqlauth_port, "3306"}, + /* Database used for authentication */ + {"mysqlauthdb", &mysqlauth_db, "authdb"}, + /* Username to connect to db */ + {"mysqlusername", &mysqlauth_username, NULL}, + /* Password to connect to db */ + {"mysqlpassword", &mysqlauth_password, NULL}, + /* Alias for mysqlusername */ + {"mysqlauthusername", &mysqlauth_username, NULL}, + /* Alias for mysqlpassword */ + {"mysqlauthpassword", &mysqlauth_password, NULL}, + /* Table used for authentication */ + {"mysqlauthtable", &mysqlauth_table, "qpopper"}, + /* One of "cleartext", "crypt", "md5", "mysql", "all", or "both" */ + {"mysqlauthpasswordmethod", &mysqlauth_password_method, "cleartext"}, + {"mysqlauthusernamefield", &mysqlauth_username_field, "username"}, + {"mysqlauthpasswordfield", &mysqlauth_password_field, "password"}, + {"mysqlauthdomainfield", &mysqlauth_domain_field, NULL}, + /* Domain to be used if none specified */ + {"mysqlauthdefaultdomain", &mysqlauth_default_domain, ""}, + {"mysqlauthuidfield", &mysqlauth_uid_field, NULL}, + {"mysqlauthgidfield", &mysqlauth_gid_field, NULL}, + {"mysqlauthuid", &mysqlauth_uid_s, NULL}, + {"mysqlauthuidname", &mysqlauth_uid_name, NULL}, + {"mysqlauthgid", &mysqlauth_gid_s, NULL}, + {"mysqlauthgidname", &mysqlauth_gid_name, NULL}, + {"mysqlauthacctstatusfield", &mysqlauth_acct_status_field, NULL}, + {"mysqlshellfield", &mysqlauth_shell_field, NULL}, + {(char *)NULL, (char **)NULL, NULL} +}; + +int +load_popper_conf(p) +POP * p; +{ + FILE *config; + char buf[BUFSIZE]; + struct config_options *c_options; + char *tkp; + char key[BUFSIZE], value[BUFSIZE]; + + config = fopen (MYSQL_CONF,"r"); + if(!config) { + pop_log(p, POP_PRIORITY, HERE, + "Unable to open mysql config file %s", MYSQL_CONF); + return POP_FAILURE; + } + + c_options = options; + while(c_options->name) { + *(c_options->value) = c_options->default_value; + c_options++; + } + + + + while (fgets(buf, BUFSIZE, config)) { + buf[strlen(buf)-1]=0; + if (buf[0] == '#' || buf[0] == '\0') { + continue; + } + sscanf(buf, "%s %s", key, value); + + /* Lowercase string */ + for(tkp=key; *tkp; tkp++) *tkp = tolower(*tkp); + + c_options = options; + while(c_options->name) { + if(!strcmp(key, c_options->name)) { + *(c_options->value) = (char *)malloc(strlen(value)+1); + strcpy(*(c_options->value),value); + break; + } + c_options++; + } + } + + fclose(config); + +/* Check for config dependencies */ + + if(!(mysqlauth_uid_field || mysqlauth_uid_s || mysqlauth_uid_name)) { + pop_log(p, POP_PRIORITY, HERE, + "Must specify one of MySqlAuthUidField or MysqlAuthUid " + "or MysqlAuthUidName" + ); + return POP_FAILURE; + } + if(!mysqlauth_uid_s && mysqlauth_uid_name) { + struct passwd *pw; + if(!(pw = getpwnam(mysqlauth_uid_name))) { + pop_log(p, POP_PRIORITY, HERE, + "MysqlAuthUidName %s cannot be found", mysqlauth_uid_name); + return POP_FAILURE; + } + mysqlauth_uid = pw->pw_uid; + + } else { + if(mysqlauth_uid_s) mysqlauth_uid = atoi(mysqlauth_uid_s); + else mysqlauth_uid = -1; + } + + if(!(mysqlauth_gid_field || mysqlauth_gid_s || mysqlauth_gid_name)) { + pop_log(p, POP_PRIORITY, HERE, + "Must specify one of MySqlAuthGidField or MysqlAuthGid " + "or MysqlAuthGidName"); + return POP_FAILURE; + } + if(!mysqlauth_gid_s && mysqlauth_gid_name) { + struct group *gr; + if(!(gr = getgrnam(mysqlauth_gid_name))) { + pop_log(p, POP_PRIORITY, HERE, + "MysqlAuthUidName %s cannot be found", mysqlauth_gid_name); + return POP_FAILURE; + } + mysqlauth_gid = gr->gr_gid; + } else { + if(mysqlauth_gid_s) mysqlauth_gid = atoi(mysqlauth_gid_s); + else mysqlauth_gid = -1; + } + if (!mysqlauth_domain_field) { + pop_log(p, POP_PRIORITY, HERE, "NOTE: Virtual domain authentication is disabled"); + } + + return POP_SUCCESS; + + +} + +#endif diff -ruN qpopper4.0.3/popper/pop_config.c qpopper4.0.3-mysql-0.4/popper/pop_config.c --- qpopper4.0.3/popper/pop_config.c Fri Jun 1 19:24:33 2001 +++ qpopper4.0.3-mysql-0.4/popper/pop_config.c Thu Mar 7 15:23:05 2002 @@ -434,7 +434,7 @@ static void skip_token (config_opt_type ttype, char **token, long *token_len, long *line_len); static void show_result (POP *p, config_table *opt, int iVal, const char *sVal, WHENCE); static error_code_type handle_value (POP *p, config_table *opt, char *pval, int plen, config_call_type CallTime); - +static char *get_hash_dir ( char *pszUser, int iMethod ); /* * Log an error message. @@ -1475,11 +1475,29 @@ { int rslt; char buf [ 256 ]; + char tempbuf [ 256 ]; struct stat stat_buf; if ( p->bUser_opts ) { +#ifdef MYSQLAUTH + /* assumes home directory? */ + strcpy(tempbuf,pwp->pw_dir); + /* tack on domain */ + if (strcmp(p->domain,"NULL")) { + strlcat ( tempbuf, p->domain, sizeof(tempbuf) ); + strlcat ( tempbuf, "/", sizeof(tempbuf) ); + } + /* tack on hashing */ + if ( p->hash_spool != 0 ) { + strlcat ( tempbuf, get_hash_dir ( p->user, p->hash_spool ), sizeof(tempbuf) ); + } + /* tack on user */ + strlcat ( tempbuf, p->user, sizeof(tempbuf) ); + rslt = Qsnprintf ( buf, sizeof(buf), "%s/.qpopper-options", tempbuf ); +#else rslt = Qsnprintf ( buf, sizeof(buf), "%s/.qpopper-options", pwp->pw_dir ); +#endif if ( rslt == -1 ) pop_log ( p, POP_PRIORITY, HERE, "Unable to build user options file name for user %s", @@ -1498,8 +1516,19 @@ } /* p->user_opts */ if ( p->bSpool_opts ) { +#ifdef MYSQLAUTH + if (strcmp(p->domain,"NULL")) { + rslt = Qsnprintf ( buf, sizeof(buf), "%s/.%s@%s.qpopper-options", + p->pCfg_spool_dir, p->user, p->domain ); + } + else { rslt = Qsnprintf ( buf, sizeof(buf), "%s/.%s.qpopper-options", p->pCfg_spool_dir, p->user ); + } +#else + rslt = Qsnprintf ( buf, sizeof(buf), "%s/.%s.qpopper-options", + p->pCfg_spool_dir, p->user ); +#endif if ( rslt == -1 ) pop_log ( p, POP_PRIORITY, HERE, "Unable to build spool options file name for user %s", @@ -1551,3 +1580,72 @@ return rslt; } + +/* + * Hashing to a spool directory helps reduce the lookup time for sites + * with thousands of mail spool files. Unix uses a linear list to + * save directory information and the following methods attempt to + * improve the performance. + * + * Method 1: add the value of the first 5 chars mod 26 and open the + * spool file in the directory 'a' - 'z'/user. + * Brian Buhrow + * + * Method 2: Use the first 2 characters to determine which mail spool + * to open. E.g., /usr/spool/u/s/user. + * Larry Schwimmer + * (if only one character it is repeated.) + * + * All these methods require that local mail delivery and client programs + * use the same algorithm. Only one method to a customer :-) + */ + +static char hash_buf [ 5 ]; + +static char * +get_hash_dir ( char *pszUser, int iMethod ) +{ + if ( iMethod == 1 ) { + int seed = 0; + + /*Now, perform the hash*/ + + switch ( strlen(pszUser) ) { + case 1: + seed = ( pszUser[0] ); + break; + case 2: + seed = ( pszUser[0] + pszUser[1] ); + break; + case 3: + seed = ( pszUser[0] + pszUser[1] + pszUser[2] ); + break; + case 4: + seed = ( pszUser[0] + pszUser[1] + pszUser[2]+ pszUser[3] ); + break; + default: + seed = ( pszUser[0] + pszUser[1] + pszUser[2] + + pszUser[3] + pszUser[4] ); + break; + } /* switch on pszUser length */ + + hash_buf [ 0 ] = (char) ( (seed % 26) + 'a' ); + hash_buf [ 1 ] = '/'; + hash_buf [ 2 ] = '\0'; + + return hash_buf; + } /* hash_spool == 1 */ + else + if ( iMethod == 2 ) { + hash_buf [ 0 ] = *pszUser; + hash_buf [ 1 ] = '/'; + hash_buf [ 2 ] = ( *(pszUser + 1) ? *(pszUser + 1) : *pszUser ); + hash_buf [ 3 ] = '/'; + hash_buf [ 4 ] = '\0'; + return hash_buf; + } /* hash_spool == 2 */ + else + return NULL; +} + + diff -ruN qpopper4.0.3/popper/pop_dropcopy.c qpopper4.0.3-mysql-0.4/popper/pop_dropcopy.c --- qpopper4.0.3/popper/pop_dropcopy.c Fri Jun 1 19:24:34 2001 +++ qpopper4.0.3-mysql-0.4/popper/pop_dropcopy.c Mon Oct 29 13:54:24 2001 @@ -1203,6 +1203,14 @@ int rslt; time_t time_locked = 0; time_t my_timer = 0; + char buffer [ MAXLINELEN ]; + mode_t my_umask; + mode_t spool_mode; + mode_t temp_mode = 0x1C0; + uid_t spool_owner; + gid_t spool_group; + char *ptr; + if ( p->bDo_timing ) @@ -1304,18 +1312,9 @@ } /* if (p->bulldir) */ #endif /* BULLDB */ - if ( p->hash_spool > 0 && p->bCheck_hash_dir ) { - /* - * Make sure the path to the spool file exists - */ - char buffer [ MAXLINELEN ]; - mode_t my_umask; - mode_t spool_mode; - mode_t temp_mode = 0x1C0; - uid_t spool_owner; - gid_t spool_group; - char *ptr; - +/* we do this here because we need it for VIRTUAL DOMAIN setup */ +/* AND/OR hashed directories */ + /* * Get the path name. */ @@ -1353,6 +1352,50 @@ (unsigned int) my_umask, 0000, (int) getuid(), (int) geteuid() ); +#ifdef MYSQLAUTH +/* we need to create the virtual domain directory if it doesn't exist */ + if (strcmp(p->domain,"NULL")) { + if (p->hash_spool > 0) { + ptr=strdup(buffer); + ptr[strlen(ptr)-(p->hash_spool*2)]='\0'; + } /* p->hash_spool */ + else ptr=strdup(buffer); + + if ( stat ( ptr, &mybuf ) == -1 && errno == ENOENT ) { + /* The directory doesn't exit -- create it */ + if ( mkdir ( ptr, temp_mode ) == -1 ) + return pop_msg ( p, POP_FAILURE, HERE, + "[SYS/TEMP] Unable to create virtual spool directory " + "%s (%04o): %s (%d)", + ptr, (int) temp_mode, STRERROR(errno), errno ); + if ( chmod ( ptr, spool_mode ) == -1 ) + return pop_msg ( p, POP_FAILURE, HERE, + "[SYS/TEMP] Unable to chmod of %s to %04o: " + "%s (%d)", + ptr, (int) spool_mode, STRERROR(errno), errno ); + if ( chown ( ptr, spool_owner, spool_group ) == -1 ) + return pop_msg ( p, POP_FAILURE, HERE, + "[SYS/TEMP] Unable to set owner/group of spool " + "directory %s to %d/%d: %s (%d)", + ptr, (int) spool_owner, (int) spool_group, + STRERROR(errno), errno ); + + if ( DEBUGGING ) { + if ( stat ( ptr, &mybuf ) != 0 ) + return pop_msg ( p, POP_FAILURE, HERE, + "[SYS/TEMP] Unable to access newly-created " + "virtual dir %s: %s (%d)", + ptr, STRERROR(errno), errno ); + DEBUG_LOG4 ( p, "Created %s; mode=%04o; owner=%d; group=%d", + ptr, (unsigned int) mybuf.st_mode, + (int) mybuf.st_uid, (int) mybuf.st_gid ); + } /* DEBUGGING */ + } /* directory doesn't exit */ + *ptr = '/'; + } /* virtual domain exists */ +#endif + + if ( p->hash_spool > 0 && p->bCheck_hash_dir ) { /* * In theory, we could just create the new directories with mkdir(2) * or mknod(2), and pass in the desired mode. But this causes @@ -1408,7 +1451,7 @@ buffer ); } } /* HASH_SPOOL == 2 */ - + if ( stat ( buffer, &mybuf ) == -1 && errno == ENOENT ) { /* The directory doesn't exit -- create it */ DEBUG_LOG2 ( p, "HASH_SPOOL; Creating spool path: %s (mode %04o)", @@ -1456,14 +1499,25 @@ p->orig_group = pwp->pw_gid; /* save original group */ + DEBUG_LOG1 ( p, "saving old gid %d", p->orig_group); + +#ifdef MYSQLAUTH + /* dont do anything, we want to keep our pw_gid */ +#else #ifdef BINMAIL_IS_SETGID # if BINMAIL_IS_SETGID > 1 pwp->pw_gid = (gid_t)BINMAIL_IS_SETGID; + DEBUG_LOG1 ( p, "setting new gid to binmail gid of %d", pwp->pw_gid); # else - if ( !stat(p->pCfg_spool_dir, &mybuf) ) + if ( !stat(p->pCfg_spool_dir, &mybuf) ) { pwp->pw_gid = mybuf.st_gid; + DEBUG_LOG1 ( p, "setting new gid to spooldir gid of %d", pwp->pw_gid); + } # endif /* BINMAIL_IS_SETGID > 1 */ +#else + DEBUG_LOG1 ( p, "setting new gid to old saved gid of %d", pwp->pw_gid); #endif /* BINMAIL_IS_SETGID */ +#endif /* MYSQLAUTH */ /* * Now we run as the user. diff -ruN qpopper4.0.3/popper/pop_pass.c qpopper4.0.3-mysql-0.4/popper/pop_pass.c --- qpopper4.0.3/popper/pop_pass.c Fri Jun 1 19:24:35 2001 +++ qpopper4.0.3-mysql-0.4/popper/pop_pass.c Wed Mar 6 00:04:53 2002 @@ -124,6 +124,26 @@ #include #include "popper.h" +/* + * Some old OSes don't have srandom, but do have srand + */ +#ifndef HAVE_SRANDOM +# include +# define srandom srand +# define random rand +#else + extern void srandom(); +#endif /* HAVE_SRANDOM */ + +#ifdef MYSQLAUTH +# include "md5.h" +# define MYSQL_CRYPT_LEN 65 +#endif /* MYSQLAUTH */ + +#ifdef LOG_LOGIN_MYSQL +# include +#endif + #ifdef KERBEROS # ifdef KRB5 # include @@ -1264,6 +1284,26 @@ *secretkey = '\0'; #endif /* SECURENISPLUS */ +#ifdef MYSQLAUTH + int crypto_crypt = 0, crypto_mysql = 0, crypto_md5 = 0, crypto_plain = 0; + register char *cp2; + char buffer[BUFSIZ]; + register unsigned char *dp; + unsigned char *ep, digest[16]; + char *scrambled_password = NULL; + char crypted_pw[36]; + char *userdomain; + MD5_CTX mdContext; +#endif /* MYSQLAUTH */ + +#ifdef LOG_LOGIN_MYSQL + MYSQL mysql; + #define QBUF_LEN 255 + char qbuf[QBUF_LEN]; + MYSQL_RES *result; + unsigned int num_rows; +#endif + /* * Is the user not authorized to use POP? */ @@ -1291,6 +1331,132 @@ return ( pop_msg ( p, POP_FAILURE, HERE, ERRMSG_PW, p->user ) ); } +#ifdef MYSQLAUTH + DEBUG_LOG6 ( p, + "%s: pop_pass sql data: pw_name=\"%s\" pw_passwd=\"xxx\" pw_dir=\"%s\" pw_uid=\"%d\" pw_gid=\"%d\" pw_shell=\"%s\"", + p->user, + pwp->pw_name, + pwp->pw_dir, + pwp->pw_uid, + pwp->pw_gid, + pwp->pw_shell + ); + + userdomain = (char *)malloc(strlen(p->user)+strlen(p->domain)+2); + strcpy(userdomain,p->user); + if (strcmp(p->domain,"NULL")) { + strcat(userdomain,"@"); + strcat(userdomain,p->domain); + } + +/* Set all of the relevant authentication methods to try */ + if (!strcmp(mysqlauth_password_method,"any")) { + crypto_crypt++; + crypto_mysql++; + crypto_md5++; + crypto_plain++; + } + else if (!strcmp(mysqlauth_password_method,"both")) { + /* for backwards compatibility */ + crypto_crypt++; + crypto_plain++; + } + else if (!strcmp(mysqlauth_password_method,"crypt")) { + crypto_crypt++; + } + else if (!strcmp(mysqlauth_password_method,"mysql")) { + crypto_mysql++; + } + else if (!strcmp(mysqlauth_password_method,"md5")) { + crypto_md5++; + } + else if (!strcmp(mysqlauth_password_method,"cleartext")) { + crypto_plain++; + } + else { + /* default to plaintext */ + crypto_plain++; + } + + if (crypto_crypt != 0) { + strcpy(crypted_pw, crypt(p->pop_parm[1], pwp->pw_passwd)); + + if (!strcmp(pwp->pw_passwd,crypted_pw)) { + DEBUG_LOG3 ( p, "%s: succcessful crypt sql authentication for user %s (%s)", + p->user, userdomain, pwp->pw_name); + goto auth_ok; + } + } /* crypto_crypt */ + if (crypto_mysql != 0) { + unsigned int t; + unsigned char t1, t2; + + if ((scrambled_password = + malloc((size_t) (MYSQL_CRYPT_LEN + 2))) == NULL) { + pop_log(p, POP_FAILURE, HERE, + "%s: crypto_mysql: bad malloc for scrambled_password!",p->user); + goto auth_bad; + } + /* seed random with the current time to nearest second */ + srandom( (unsigned int) time((TIME_T *)0) ); + + t = random(); + t1 = t & 0xff; + t2 = (t >> 8) & 0xff; + scrambled_password[MYSQL_CRYPT_LEN] = (char) t1; + scrambled_password[MYSQL_CRYPT_LEN + 1] = (char) t2; + make_scrambled_password(scrambled_password, p->pop_parm[1]); + if ((unsigned char) scrambled_password[MYSQL_CRYPT_LEN] != t1 || + (unsigned char) scrambled_password[MYSQL_CRYPT_LEN + 1] != t2) { + for (;;) { + *scrambled_password++ = 0; + } + } + + if (!strcmp(pwp->pw_passwd,scrambled_password)) { + DEBUG_LOG3 ( p, "%s: succcessful mysql sql authentication for user %s (%s)", + p->user, userdomain, pwp->pw_name); + goto auth_ok; + } + } /* crypto_mysql */ + if (crypto_md5 != 0) { + + MD5Init ( &mdContext ); + if (p->pop_parm[1] != NULL && *p->pop_parm[1] != 0) { + MD5Update ( &mdContext, (unsigned char *) p->pop_parm[1], strlen(p->pop_parm[1]) ); + } + MD5Final ( digest, &mdContext ); + + cp2 = buffer; + for (ep = (dp = digest) + sizeof digest / sizeof digest[0]; + dp < ep; + cp2 += 2) + (void) sprintf (cp2, "%02x", *dp++ & 0xff); + *cp2 = '\0'; + + if (!strcmp(pwp->pw_passwd, buffer)) { + DEBUG_LOG3 ( p, "%s: succcessful md5 sql authentication for user %s (%s)", + p->user, userdomain, pwp->pw_name); + goto auth_ok; + } + } /* crypto_md5 */ + if (crypto_plain != 0) { + if (!strcmp(pwp->pw_passwd,p->pop_parm[1])) { + DEBUG_LOG3 ( p, "%s: succcessful cleartext sql authentication for user %s (%s)", + p->user, userdomain, pwp->pw_name); + goto auth_ok; + } + } /* crypto_plain */ + /* if we get here, authentication failed */ + auth_bad: + sleep(SLEEP_SECONDS); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_PW, userdomain)); + +auth_ok: + DEBUG_LOG3 ( p, "%s: end of sql authentication for user %s (%s)", + p->user, userdomain, pwp->pw_name); +#else /* not MYSQLAUTH */ + #ifdef SECURENISPLUS /* * we must do this keyserv stuff (as well as auth_user()!) as the user @@ -1387,6 +1553,8 @@ seteuid ( uid_save ); #endif /* SECURENISPLUS */ +#endif /* MYSQLAUTH */ + /* * Check if server mode should be set or reset based on group membership. */ @@ -1436,6 +1604,81 @@ * Authorization completed successfully */ +#ifdef LOG_LOGIN_MYSQL + DEBUG_LOG1 ( p, "%s: Doing log-login sql", p->user); + mysql_init(&mysql); + if(!mysql_real_connect(&mysql,mysqlauth_host,mysqlauth_username, + mysqlauth_password, mysqlauth_db, + atoi(mysqlauth_port), NULL, 0 )) { + pop_log(p, POP_FAILURE, HERE, + "Couldn't connect to the authentication database (%s) ", + mysql_error(&mysql)); + return(pop_msg(p, POP_FAILURE, HERE, + "Couldn't connect to the authentication database")); + } + else { + DEBUG_LOG5 ( p, "%s: Connected to %s:%s db %s as %s for log-login", + p->user,mysqlauth_host,mysqlauth_port,mysqlauth_db,mysqlauth_username); + } + snprintf(qbuf, QBUF_LEN, + "SELECT ip FROM relays WHERE ip = '%s'",p->ipaddr); + if (mysql_query(&mysql, (char *)qbuf) < 0) { + pop_log(p, POP_FAILURE, HERE, "query (%s) failed (%s)", qbuf, + mysql_error(&mysql)); + mysql_close(&mysql); + return(pop_msg(p, POP_FAILURE, HERE, "Logging query check failure")); + } + else { + DEBUG_LOG3 ( p, "%s: Ran log-login sql query \"%s\" against db %s", + p->user, qbuf, mysqlauth_db); + } + if(!(result = mysql_store_result(&mysql))) { + pop_log(p, POP_FAILURE, HERE, "Logging query check result failed (%s)", mysql_error(&mysql)); + mysql_close(&mysql); + return(pop_msg(p, POP_FAILURE, HERE, "Logging query check result failed")); + } + else { + DEBUG_LOG2 ( p, "%s: Successfully got log-login sql result from db %s", + p->user, mysqlauth_db); + } + num_rows = mysql_num_rows(result); + mysql_free_result(result); + if (num_rows==0) { + /* make new row */ + snprintf(qbuf, QBUF_LEN, + "INSERT INTO relays (ip, ts) VALUES ('%s','%ld')", + p->ipaddr,time(0)); + if (mysql_query(&mysql, (char *)qbuf) < 0) { + pop_log(p, POP_FAILURE, HERE, "query (%s) failed (%s)", qbuf, + mysql_error(&mysql)); + mysql_close(&mysql); + return(pop_msg(p, POP_FAILURE, HERE, "Logging query new failure")); + } + else { + DEBUG_LOG3 ( p, "%s: Ran log-login sql query \"%s\" against db %s", + p->user, qbuf, mysqlauth_db); + } + } /* if !num_rows */ + else { + /* update row with current ts */ + snprintf(qbuf, QBUF_LEN, + "UPDATE relays SET ts = '%ld' WHERE ip = '%s'", + time(0),p->ipaddr); + if (mysql_query(&mysql, (char *)qbuf) < 0) { + pop_log(p, POP_FAILURE, HERE, "query (%s) failed (%s)", qbuf, + mysql_error(&mysql)); + mysql_close(&mysql); + return(pop_msg(p, POP_FAILURE, HERE, "Logging query update failure")); + } + else { + DEBUG_LOG3 ( p, "%s: Ran log-login sql query \"%s\" against db %s", + p->user, qbuf, mysqlauth_db); + } + } /* else */ + mysql_close(&mysql); + DEBUG_LOG1 ( p, "%s: Done doing log-login sql", p->user); +#endif + if ( p->pLog_login != NULL ) do_log_login ( p ); @@ -1451,4 +1694,5 @@ (p->msg_count - p->visible_msg_count), p->drop_size ) ); } + diff -ruN qpopper4.0.3/popper/pop_user.c qpopper4.0.3-mysql-0.4/popper/pop_user.c --- qpopper4.0.3/popper/pop_user.c Fri Jun 1 23:21:14 2001 +++ qpopper4.0.3-mysql-0.4/popper/pop_user.c Thu Mar 7 14:59:57 2002 @@ -95,6 +95,11 @@ #include "popper.h" #include "string_util.h" +#ifdef MYSQLAUTH +# include +# define SLEEP_SECONDS 10 +#endif + /* * When AUTHON is defined, SCRAM and/or APOP authentication is available. */ @@ -111,6 +116,14 @@ extern char *ERRMSG_PW; +/* + * MYSQLAUTH STUFF + */ +char *ERRMSG_ACCT = "[AUTH] \"%s\": %s account"; +char *ERRMSG_NULL = "[AUTH] \"%s\": %s field is NULL!"; +char *ERRMSG_QUERY = "[AUTH] \"%s\": Authentication query failed. Account may not exist."; +#define MYSQL_DEFAULT_HOMEDIR "/home" + /* * user: Prompt for the user name at the start of a POP session @@ -138,7 +151,23 @@ int i; int bFoundUser = FALSE; #endif /* AUTHON */ +#ifdef MYSQLAUTH + MYSQL mysql; + #define QBUF_LEN 255 + char qbuf[QBUF_LEN]; + char *mqbuf; + MYSQL_RES *result; + MYSQL_ROW row; + int a=0; + int uid_field_num=0, gid_field_num=0, shell_field_num=0; + int acct_status_field_num=0, acct_status; + int qbufleft; + int slen; + unsigned long *lengths; + char *userdomain; +#endif + char *atpos; size_t user_name_len = 0; struct passwd *pw = NULL; @@ -156,9 +185,13 @@ /* * Trim domain name */ - if ( p->bTrim_domain ) + if ( p->bTrim_domain ) { +#ifdef MYSQLAUTH + if (!mysqlauth_domain_field) +#endif trim_domain ( p, p->pop_parm[1] ); - + } + #if defined(KERBEROS) && defined(KRB4) && !defined(KUSEROK) if ( p->bKerberos && strcmp(p->pop_parm[1], p->user) ) { pop_log ( p, POP_WARNING, HERE, @@ -196,7 +229,34 @@ p->pop_parm[1] ); user_name_len = sizeof(p->user) -1; } + +#ifdef MYSQLAUTH + if(mysqlauth_domain_field) + { + atpos=strrchr(p->pop_parm[1],'@'); + if(!atpos) atpos=strrchr(p->pop_parm[1],'#'); + if(atpos) { + int domain_name_len; + atpos++; /* Move passed the '@' */ + domain_name_len = p->pop_parm[1]+strlen(p->pop_parm[1])-atpos; + strncpy(p->domain, atpos, domain_name_len); + pop_lower(p->domain); + user_name_len -= domain_name_len+1; + p->domain[domain_name_len] = 0; + } else { + /* No domain part - use default */ + strcpy(p->domain, mysqlauth_default_domain); + } + } + else strcpy(p->domain, "NULL"); + + DEBUG_LOG3 ( p, "%s: Got virtual domain \"%s\" from user \"%s\"", + p->pop_parm[1], p->domain, p->pop_parm[1]); +#endif +if (atpos) + strlcpy ( p->user, p->pop_parm[1], user_name_len ); +else strlcpy ( p->user, p->pop_parm[1], sizeof(p->user) ); #ifdef SCRAM @@ -207,6 +267,258 @@ * Cache passwd struct for use later; this memory gets freed at the end * of the session. */ +#ifdef MYSQLAUTH + userdomain = (char *)malloc(strlen(p->user)+strlen(p->domain)+2); + strcpy(userdomain,p->user); + if (strcmp(p->domain,"NULL")) { + strcat(userdomain,"@"); + strcat(userdomain,p->domain); + } + + mysql_init(&mysql); + if(!mysql_real_connect(&mysql,mysqlauth_host,mysqlauth_username, + mysqlauth_password, mysqlauth_db, + atoi(mysqlauth_port), NULL, 0 )) { + pop_log(p, POP_FAILURE, HERE, + "Couldn't connect to the authentication database (%s) ", + mysql_error(&mysql)); + return(pop_msg(p, POP_FAILURE, HERE, + "Couldn't connect to the authentication database")); + } + else { + DEBUG_LOG5 ( p, "%s: Connected to %s:%s db %s as %s for authentication", + userdomain,mysqlauth_host,mysqlauth_port,mysqlauth_db,mysqlauth_username); + } + +#define MYSTRCAT(STRING) do { strncpy(mqbuf, STRING, qbufleft); \ + slen = strlen(STRING); \ + qbufleft -= slen; \ + mqbuf += slen; } while(0) + +#define MYSTRCATCHR(C) do { \ + if(qbufleft>0) { \ + *mqbuf++=C; \ + *mqbuf = '\0'; \ + qbufleft--; \ + } \ + } while(0) + +#define MYSTRCATESC(STRING) do { \ + slen = strlen(STRING); \ + slen = mysql_escape_string(mqbuf, STRING, \ + (qbufleft/2 < slen ? qbufleft/2 : slen)); \ + mqbuf += slen; \ + qbufleft -= slen; \ + } while(0) + + + mqbuf = qbuf; + qbufleft = QBUF_LEN-1; + + MYSTRCAT("SELECT "); + MYSTRCAT(mysqlauth_password_field); + if(mysqlauth_uid_field) { + uid_field_num = ++a; + MYSTRCATCHR(','); + MYSTRCAT(mysqlauth_uid_field); + } + if(mysqlauth_gid_field) { + gid_field_num = ++a; + MYSTRCATCHR(','); + MYSTRCAT(mysqlauth_gid_field); + } + if(mysqlauth_shell_field) { + shell_field_num = ++a; + MYSTRCATCHR(','); + MYSTRCAT(mysqlauth_shell_field); + } + if(mysqlauth_acct_status_field) { + acct_status_field_num = ++a; + MYSTRCATCHR(','); + MYSTRCAT(mysqlauth_acct_status_field); + } + + + MYSTRCAT(" FROM "); + MYSTRCAT(mysqlauth_table); + MYSTRCAT(" WHERE "); + MYSTRCAT(mysqlauth_username_field); + MYSTRCAT("= '"); + MYSTRCATESC(p->user); + MYSTRCATCHR('\''); + if(mysqlauth_domain_field) { + MYSTRCAT(" AND "); + MYSTRCAT(mysqlauth_domain_field); + MYSTRCAT(" = '"); + MYSTRCATESC(p->domain); + MYSTRCATCHR('\''); + } + + if (mysql_query(&mysql,(char *)qbuf) < 0) { + pop_log(p, POP_FAILURE, HERE, "query (%s) failed (%s)", qbuf, + mysql_error(&mysql)); + mysql_close(&mysql); + return(pop_msg(p, POP_FAILURE, HERE, "Authentication query failed")); + } + else { + DEBUG_LOG3 ( p, "%s: Ran sql query \"%s\" against db %s", + userdomain, qbuf, mysqlauth_db); + } + + if(!(result = mysql_use_result(&mysql))) { + pop_log(p, POP_FAILURE, HERE, "query result failed (%s)", mysql_error(&mysql)); + mysql_close(&mysql); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_QUERY, userdomain)); + } + else { + DEBUG_LOG2 ( p, "%s: Successfully got sql result from db %s", + userdomain, mysqlauth_db); + } + + if(!(row = mysql_fetch_row(result))) { + pop_log(p, POP_FAILURE, HERE, "query fetch row failed (%s)", mysql_error(&mysql)); + mysql_free_result(result); + mysql_close(&mysql); + sleep(SLEEP_SECONDS); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_QUERY, userdomain)); + } + else { + DEBUG_LOG1 ( p, "%s: Successfully got sql row from result", userdomain); + } + lengths = mysql_fetch_lengths(result); + + if (mysqlauth_acct_status_field) { + /* check account status */ + if (row[acct_status_field_num] != NULL) + acct_status=atoi(row[acct_status_field_num]); + else { + mysql_free_result(result); + mysql_close(&mysql); + sleep(SLEEP_SECONDS); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_NULL, userdomain, "status")); + } + + DEBUG_LOG2 ( p, "%s: sql acct_status is \"%d\"", + userdomain, acct_status); + + if (acct_status != 1) { + mysql_free_result(result); + mysql_close(&mysql); + sleep(SLEEP_SECONDS); + switch(acct_status) { + case 0: + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_ACCT, userdomain, "disabled")); + break; + case 2: + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_ACCT, userdomain, "suspended")); + break; + case 3: + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_ACCT, userdomain, "on-hold")); + break; + } /* switch */ + } /* acct_status bad */ + } /* check status */ + + if (mysqlauth_shell_field) { + /* check shell field */ + if (row[shell_field_num] == NULL) { + mysql_free_result(result); + mysql_close(&mysql); + DEBUG_LOG1 ( p, "%s: sql shell is NULL", userdomain); + sleep(SLEEP_SECONDS); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_NULL, userdomain, "shell")); + } + else { + DEBUG_LOG2 ( p, "%s: sql shell is \"%s\"", userdomain, + row[shell_field_num]); + } + } /* check shell */ + + /* make sure we can get a password for the check in pop_pass() later */ + if (row[0] == NULL) { + mysql_free_result(result); + mysql_close(&mysql); + DEBUG_LOG1 ( p, "%s: sql password is NULL", userdomain); + sleep(SLEEP_SECONDS); + return (pop_msg(p,POP_FAILURE, HERE, ERRMSG_NULL, userdomain, "password")); + } + else { + DEBUG_LOG1 ( p, "%s: sql password is (hidden)", userdomain); + } + + pw = (struct passwd *)malloc(sizeof(struct passwd)); + +#if defined(__bsdi__) && _BSDI_VERSION >= 199608 + pw->pw_class = malloc(1); + pw->pw_class='\0'; +#endif + + pw->pw_name = malloc(strlen(p->user)+2); + strcpy(pw->pw_name, p->user); + + pw->pw_passwd = malloc(strlen(row[0])+2); + strcpy(pw->pw_passwd, row[0]); + + /* non-virtual setup will return just POP_MAILDIR */ + /* i.e. /var/spool/mail/ */ + /* virtual setup will return POP_MAILDIR + domain */ + /* i.e. /var/spool/mail/mydomain.com/ */ + /* NOTE: hashing is done afterwards! */ + /* so a virtual setup with a hash of 2 might result in */ + /* /var/spool/mail/mydomain.com/u/s/user */ + if ( p->pHome_dir_mail != NULL ) { + pw->pw_dir = malloc(strlen(MYSQL_DEFAULT_HOMEDIR)+2); + strcpy(pw->pw_dir, MYSQL_DEFAULT_HOMEDIR); + strcat(pw->pw_dir, "/"); + } + else if (strcmp(p->domain,"NULL")) { + pw->pw_dir = malloc(strlen(POP_MAILDIR)+strlen(p->domain)+4); + strcpy(pw->pw_dir, POP_MAILDIR); + strcat(pw->pw_dir, "/"); + strcat(pw->pw_dir,p->domain); + strcat(pw->pw_dir, "/"); + } + else { + pw->pw_dir = malloc(strlen(POP_MAILDIR)+2); + strcpy(pw->pw_dir, POP_MAILDIR); + } + + if(mysqlauth_shell_field) { + pw->pw_shell = malloc(strlen(row[shell_field_num])+2); + strcpy(pw->pw_shell, row[shell_field_num]); + } else { + pw->pw_shell = malloc(12); + strcpy(pw->pw_shell, "/bin/false"); + } + if(mysqlauth_uid_field) { + pw->pw_uid = atoi(row[uid_field_num]); + } else { + pw->pw_uid = mysqlauth_uid; + } + if(mysqlauth_gid_field) { + pw->pw_gid = atoi(row[gid_field_num]); + } else { + pw->pw_gid = mysqlauth_gid; + } + + mysql_free_result(result); + mysql_close(&mysql); + p->pw = *pw; + + DEBUG_LOG6 ( p, + "%s: pop_user sql data: pw_name=\"%s\" pw_passwd=\"xxx\" pw_dir=\"%s\" pw_uid=\"%d\" pw_gid=\"%d\" pw_shell=\"%s\"", + p->user, + p->pw.pw_name, + p->pw.pw_dir, + p->pw.pw_uid, + p->pw.pw_gid, + p->pw.pw_shell + ); + + DEBUG_LOG3 ( p, "%s: home via mysql (%d): '%s'", + p->user, strlen(p->pw.pw_dir), p->pw.pw_dir ); + +#else /* not MYSQLAUTH */ pw = getpwnam ( p->user ); /* get pointer to info */ if ( pw != NULL ) { p->pw = *pw; /* copy it */ @@ -214,6 +526,7 @@ DEBUG_LOG2 ( p, "home (%d): '%s'", strlen(p->pw.pw_dir), p->pw.pw_dir ); } +#endif /* MYSQLAUTH */ #ifdef SCRAM_ONLY return ( pop_auth_fail ( p, POP_FAILURE, HERE, diff -ruN qpopper4.0.3/popper/popper.c qpopper4.0.3-mysql-0.4/popper/popper.c --- qpopper4.0.3/popper/popper.c Fri Jun 1 19:24:36 2001 +++ qpopper4.0.3-mysql-0.4/popper/popper.c Mon Oct 29 13:54:24 2001 @@ -108,6 +108,26 @@ int pop_timeout = POP_TIMEOUT; +#ifdef MYSQLAUTH +char *mysqlauth_username; +char *mysqlauth_password; +char *mysqlauth_host; +char *mysqlauth_port; +char *mysqlauth_db; +char *mysqlauth_table; +char *mysqlauth_username_field; +char *mysqlauth_password_field; +char *mysqlauth_password_method; +char *mysqlauth_gid_field; +char *mysqlauth_uid_field; +uid_t mysqlauth_uid; +gid_t mysqlauth_gid; +char *mysqlauth_domain_field; +char *mysqlauth_default_domain; +char *mysqlauth_acct_status_field; +char *mysqlauth_shell_field; +#endif + #ifdef _DEBUG POP *global_debug_p = NULL; #endif @@ -167,6 +187,11 @@ */ if ( pop_init ( &p, argc, argv ) != POP_SUCCESS ) EXIT ( 1 ); + +#ifdef MYSQLAUTH + if (load_popper_conf(&p) != POP_SUCCESS) + EXIT( 1 ); +#endif DEBUG_LOG1 ( &p, "before TLS; tls_support==%d", p.tls_support ); diff -ruN qpopper4.0.3/popper/popper.h qpopper4.0.3-mysql-0.4/popper/popper.h --- qpopper4.0.3/popper/popper.h Fri Jun 1 19:24:36 2001 +++ qpopper4.0.3-mysql-0.4/popper/popper.h Mon Oct 29 13:54:24 2001 @@ -61,6 +61,26 @@ #include /* this needs to be after system .h files */ +#ifdef MYSQLAUTH +extern char *mysqlauth_username; +extern char *mysqlauth_password; +extern char *mysqlauth_host; +extern char *mysqlauth_port; +extern char *mysqlauth_db; +extern char *mysqlauth_table; +extern char *mysqlauth_username_field; +extern char *mysqlauth_password_field; +extern char *mysqlauth_password_method; +extern char *mysqlauth_domain_field; +extern char *mysqlauth_default_domain; +extern char *mysqlauth_gid_field; +extern char *mysqlauth_uid_field; +extern uid_t mysqlauth_uid; +extern gid_t mysqlauth_gid; +extern char *mysqlauth_acct_status_field; +extern char *mysqlauth_shell_field; +#endif + #ifdef BULLDB # undef DBM /* used by mts.c and ndbm.h */ # ifdef GDBM @@ -90,7 +110,12 @@ #define TAB 9 #define NEWLINE '\n' -#define MAXUSERNAMELEN 65 +#ifdef MYSQLAUTH +# define MAXUSERNAMELEN 128 +# define MAXDOMAINNAMELEN 64 +#else +# define MAXUSERNAMELEN 65 +#endif #define MAXDROPLEN 256 #define MAXLINELEN 1024 #define MAXMSGLINELEN MAXLINELEN @@ -538,6 +563,9 @@ BOOL bDowncase_user; /* TRUE to downcase user name */ BOOL bTrim_domain; /* TRUE to trim domain from user name */ char user[MAXUSERNAMELEN]; /* Name of the POP user */ +#ifdef MYSQLAUTH + char domain[MAXDOMAINNAMELEN]; /* Name of domain user logs in with */ +#endif #if defined(__bsdi__) && _BSDI_VERSION >= 199608 char * style; /* style of auth used */ @@ -806,6 +834,10 @@ void do_log_login (POP *p); int qpopper ( int argc, char *argv[] ); + +#ifdef MYSQLAUTH +int load_popper_conf (POP *p); +#endif extern char *pwerrmsg; diff -ruN qpopper4.0.3/popper/version.h qpopper4.0.3-mysql-0.4/popper/version.h --- qpopper4.0.3/popper/version.h Fri Jun 1 19:24:37 2001 +++ qpopper4.0.3-mysql-0.4/popper/version.h Mon Mar 4 16:04:41 2002 @@ -25,7 +25,13 @@ # endif /* KRB5 */ #else /* not KERBEROS */ -# define VERS_SUF1 "" + +# ifdef MYSQLAUTH +# define VERS_SUF1 "-mysql-0.4" +# else +# define VERS_SUF1 "" +# endif + #endif /* KERBEROS */ #ifdef _DEBUG