v. 2021.04.18 sql-aliasdomains patch for vpopmail-5.4.33 by Roberto Puzzanghera This patch makes vpopmail save domain aliases to MySQL. In this case the dovecot's sql auth driver will be aware of domain aliases, provided that you modify the sql query accordingly. More info here https://notes.sagredo.eu/en/qmail-notes-185/dovecot-vpopmail-auth-driver-removal-241.html == Settings * An autoreconf is needed as I modified the original configure.in and Makefile.am files autoreconf -f -i ./configure \ --enable-auth-module=mysql \ --enable-sql-aliasdomains (default) * Adjust your dovecot-sql.conf.ext in order to auth both real and alias domains: (more info here https://notes.sagredo.eu/en/qmail-notes-185/installing-dovecot-and-sieve-on-a-vpopmail-qmail-server-28.html#sql) password_query = SELECT \ CONCAT(vpopmail.pw_name, '@', vpopmail.pw_domain) AS user, \ vpopmail.pw_passwd AS password, \ FROM `vpopmail` \ LEFT JOIN aliasdomains ON aliasdomains.alias='%d' \ WHERE \ vpopmail.pw_name = '%n' \ AND \ (vpopmail.pw_domain = '%d' OR vpopmail.pw_domain = aliasdomains.domain) user_query = \ SELECT \ vpopmail.pw_dir AS home, \ 89 AS uid, \ 89 AS gid, \ CONCAT('*:bytes=', REPLACE(SUBSTRING_INDEX(vpopmail.pw_shell, 'S', 1), 'NOQUOTA', '0')) AS quota_rule \ FROM vpopmail \ LEFT JOIN aliasdomains ON aliasdomains.alias='%d' \ WHERE \ vpopmail.pw_name = '%n' \ AND \ (vpopmail.pw_domain = '%d' OR vpopmail.pw_domain = aliasdomains.domain) \ AND \ ('%a'!='995' or !(vpopmail.pw_gid & 2)) \ AND \ ('%r'!='localhost' or !(vpopmail.pw_gid & 4)) \ AND \ ('%r'='localhost' or '%a'!='993' or !(vpopmail.pw_gid & 8)) * Create/delete aliasdomains in the usual way with vaddaliasdomain/vdeldomain * If you already have aliasdomains, you have to populate the dbtable. You can use my "vsavealiasdomains" program to save all your domain aliases to MySQL. Type "vsavealiasadomains -A" to save all your domain aliases to MySQL. Type "vsavealiasadomains -h" for more options. =============================================================================================== diff -ruN vpopmail-5.4.33/Makefile.am vpopmail-5.4.33-patched/Makefile.am --- vpopmail-5.4.33/Makefile.am 2011-02-28 18:00:45.000000000 +0100 +++ vpopmail-5.4.33-patched/Makefile.am 2021-04-13 13:50:37.047631256 +0200 @@ -31,7 +31,7 @@ vdeldomain vpasswd vadduser vdeluser vaddaliasdomain vsetuserquota \ vpopbull vdeloldusers vmoduser valias vuserinfo vmkpasswd vipmap \ vdominfo vconvert vkill vmoddomlimits vchangepw dotqmail2valias \ - vpopmaild vlist authvchkpw vusagec + vpopmaild vlist authvchkpw vusagec vsavealiasdomains vusagec_SOURCES = vusagec.c client.c conf.c ippp.c vusagec_LDADD = libvpopmail.a @auth_libs@ @@ -114,6 +114,9 @@ vmoddomlimits_SOURCES = vmoddomlimits.c vmoddomlimits_LDADD = libvpopmail.a @auth_libs@ +vsavealiasdomains_SOURCES = vsavealiasdomains.c +vsavealiasdomains_LDADD = libvpopmail.a @auth_libs@ + DEFS=-I. @auth_inc@ install: install-recursive vusage-msg diff -ruN vpopmail-5.4.33/configure.in vpopmail-5.4.33-patched/configure.in --- vpopmail-5.4.33/configure.in 2011-02-28 18:00:45.000000000 +0100 +++ vpopmail-5.4.33-patched/configure.in 2021-04-13 13:50:37.048631246 +0200 @@ -1484,6 +1484,40 @@ #---------------------------------------------------------------------- +AC_MSG_CHECKING(whether sql-aliasdomains is enabled) +AC_ARG_ENABLE(sql-aliasdomains, + [ --enable-sql-aliasdomains Creates a table for alias/domain pairs. Only valid for MySQL auth module.], + SQL_ALIASDOMAINS=$enableval, + [ + if [[ "$AUTH_MODULE" != "mysql" ]]; + then + SQL_ALIASDOMAINS=n + else + SQL_ALIASDOMAINS=y + AC_DEFINE_UNQUOTED(SQL_ALIASDOMAINS,$SQL_ALIASDOMAINS,"") + fi + ] +) + +case $SQL_ALIASDOMAINS in + 1*|y*|Y*) + AC_MSG_RESULT(yes) + if [[ "$AUTH_MODULE" != "mysql" ]]; + then + AC_MSG_ERROR(sql-aliasdomains is only supported in the MySQL authentication module.) + else + SQL_ALIASDOMAINS=1 + AC_DEFINE_UNQUOTED(SQL_ALIASDOMAINS,$SQL_ALIASDOMAINS,"") + fi + ;; + *) + AC_MSG_RESULT(no) + SQL_ALIASDOMAINS=0 + ;; +esac + +#---------------------------------------------------------------------- + AC_MSG_CHECKING(whether any discontinued --enable commands have been used) AC_ARG_ENABLE(mysql-logging, [], @@ -1848,6 +1882,16 @@ fi fi +if [[ "$AUTH_MODULE" == "mysql" ]]; +then + if test "$SQL_ALIASDOMAINS" = 1 + then + echo "SQL domain aliases = ON domain aliases saved to MySQL --enable-sql-aliasdomains (default)" + else + echo "SQL domain aliases = OFF domain aliases NOT saved to MySQL --disable-sql-aliasdomains" + fi +fi + case $ENABLE_SPAMASSASSIN in 1*|y*|Y*) echo " spamassassin = ON --enable-spamassassin" diff -ruN vpopmail-5.4.33/doc/README.sql-aliasdomains vpopmail-5.4.33-patched/doc/README.sql-aliasdomains --- vpopmail-5.4.33/doc/README.sql-aliasdomains 1970-01-01 01:00:00.000000000 +0100 +++ vpopmail-5.4.33-patched/doc/README.sql-aliasdomains 2021-04-13 13:50:37.048631246 +0200 @@ -0,0 +1,62 @@ +v. 2021.02.15 +sql-aliasdomains patch for vpopmail-5.4.33 by Roberto Puzzanghera +More info here https://notes.sagredo.eu/en/qmail-notes-185/dovecot-vpopmail-auth-driver-removal-241.html + +================================================================================================================== + +* A patch to make vpopmail store domain aliases to MySQL. This gets dovecot's sql auth driver + aware of domain aliases, provided that you modify the sql query accordingly. + More info here https://notes.sagredo.eu/en/qmail-notes-185/dovecot-vpopmail-auth-driver-removal-241.html + +* A patch which gets vpopmail to compile with gcc-10 + +== Settings + +* An autoreconf is needed as I modified the original configure.in and Makefile.am files + + autoreconf -f -i + ./configure \ + --enable-auth-module=mysql \ + --enable-sql-aliasdomains (default) + +* Adjust your dovecot-sql.conf.ext in order to auth both real and alias domains: + (more info here https://notes.sagredo.eu/en/qmail-notes-185/installing-dovecot-and-sieve-on-a-vpopmail-qmail-server-28.html#sql) + +password_query = \ + SELECT \ + CONCAT(vpopmail.pw_name, '@', vpopmail.pw_domain) AS user, \ + vpopmail.pw_passwd AS password, \ + vpopmail.pw_dir AS userdb_home, \ + 89 AS userdb_uid, \ + 89 AS userdb_gid, \ + CONCAT('*:bytes=', REPLACE(SUBSTRING_INDEX(vpopmail.pw_shell, 'S', 1), 'NOQUOTA', '0')) AS userdb_quota_rule \ + FROM `vpopmail` \ + LEFT JOIN aliasdomains ON aliasdomains.alias='%d' \ + WHERE \ + vpopmail.pw_name='%n' \ + AND \ + (vpopmail.pw_domain='%d' OR vpopmail.pw_domain=aliasdomains.domain) \ + AND \ + ('%a'!='995' OR !(vpopmail.pw_gid & 2)) \ + AND \ + ('%r'!='[WEBMAIL-IP]' OR !(vpopmail.pw_gid & 4)) \ + AND \ + ('%r'='WEBMAIL-IP' OR '%a'!='993' OR !(vpopmail.pw_gid & 8)) + +user_query = \ + SELECT \ + vpopmail.pw_dir AS home, \ + 89 AS uid, \ + 89 AS gid \ + FROM vpopmail \ + WHERE \ + vpopmail.pw_name='%n' \ + AND \ + vpopmail.pw_domain='%d' + +* Create/delete aliasdomains in the usual way with vaddaliasdomain/vdeldomain + +* If you already have aliasdomains, you have to populate the dbtable. You can use my "vsavealiasdomains" program + to save all your domain aliases to MySQL. + Type "vsavealiasadomains -A" to save all your domain aliases to MySQL. + Type "vsavealiasadomains -h" for more options. diff -ruN vpopmail-5.4.33/vmysql.c vpopmail-5.4.33-patched/vmysql.c --- vpopmail-5.4.33/vmysql.c 2011-02-28 18:00:45.000000000 +0100 +++ vpopmail-5.4.33-patched/vmysql.c 2021-04-18 13:30:52.179139945 +0200 @@ -361,8 +361,11 @@ #else /* if creation fails, don't show an error */ vauth_create_table (MYSQL_DEFAULT_TABLE, TABLE_LAYOUT, 0); - return (0); #endif +#ifdef SQL_ALIASDOMAINS + vcreate_aliasdomains_table(); +#endif + return (0); } @@ -1866,3 +1869,53 @@ return(strcmp(crypt(clear_pass,vpw->pw_passwd),vpw->pw_passwd)); } + + +/************************************************************************/ +void vcreate_aliasdomains_table() +{ + /* if creation fails do not throw an error */ + vauth_create_table ("aliasdomains", ALIASDOMAINS_TABLE_LAYOUT, 0); + return; +} + +/************************************************************************/ +int vcreate_sql_aliasdomain(char *domain, char *alias) +{ + int err; + + if ( (err=vauth_open_update()) != 0 ) return(err); + + qnprintf( SqlBufUpdate, SQL_BUF_SIZE, + "INSERT IGNORE INTO aliasdomains (domain,alias) VALUES ('%s','%s')", + domain, + alias ); + + vcreate_aliasdomains_table(); + if (mysql_query(&mysql_update,SqlBufUpdate)) { + fprintf(stderr, "vmysql: sql error[m]: %s\n", mysql_error(&mysql_update)); + return(-1); + } + return(0); +} + + +/************************************************************************/ +int vdelete_sql_aliasdomain(char *alias) +{ + int err; + + if ( (err=vauth_open_update()) != 0 ) return(err); + + qnprintf( SqlBufUpdate, SQL_BUF_SIZE, + "DELETE FROM aliasdomains WHERE alias='%s'", + alias ); + + vcreate_aliasdomains_table(); + if (mysql_query(&mysql_update,SqlBufUpdate)) { + fprintf(stderr, "vmysql: sql error[m]: %s\n", mysql_error(&mysql_update)); + return(-1); + } + return(0); +} + diff -ruN vpopmail-5.4.33/vmysql.h vpopmail-5.4.33-patched/vmysql.h --- vpopmail-5.4.33/vmysql.h 2011-02-28 18:00:45.000000000 +0100 +++ vpopmail-5.4.33-patched/vmysql.h 2021-04-18 13:34:44.785814439 +0200 @@ -306,3 +306,10 @@ perm_defaultquota TINYINT(2) NOT NULL DEFAULT 0" #endif +void vcreate_aliasdomains_table(); +int vdelete_sql_aliasdomain(char *alias); +int vcreate_sql_aliasdomain(char *domain, char *alias); + +#define ALIASDOMAINS_TABLE_LAYOUT "alias varchar(100) NOT NULL, \ + domain varchar(100) NOT NULL, \ + PRIMARY KEY (alias)" diff -ruN vpopmail-5.4.33/vpopmail.c vpopmail-5.4.33-patched/vpopmail.c --- vpopmail-5.4.33/vpopmail.c 2011-02-28 18:00:45.000000000 +0100 +++ vpopmail-5.4.33-patched/vpopmail.c 2021-04-13 13:50:37.050631225 +0200 @@ -554,6 +554,14 @@ fprintf (stderr, "Warning: Failed to delete domain from the assign file\n"); } +#ifdef SQL_ALIASDOMAINS + /* aliasdomain table will eventually be created */ + for(i=0; i +#include +#include +#include +#include "config.h" +#include "vpopmail.h" +#include "vauth.h" + +char Domain[MAX_BUFF]; +char Alias[MAX_BUFF]; +int SaveAll; + +void usage(); +void get_options(int argc, char **argv); +void save_all_aliases(); +void save_one_real_domain_aliases( char *Domain ); +void save_alias( char *Domain, char *Alias ); +#ifndef SQL_ALIASDOMAINS +int vcreate_sql_aliasdomain(char *Domain, char *Alias); +#endif + +int main(int argc, char *argv[]) +{ + if( vauth_open( 0 )) { + vexiterror( stderr, "Initial open." ); + } + +#ifndef SQL_ALIASDOMAINS + printf("\nPlease use option --enable-sql-aliasdomains at configure time\n\n"); + exit(-1); +#else + get_options(argc,argv); + + /* did we want to save all aliases of one single domain? */ + if ( Domain[0] > 0 && Alias[0] == 0 ) { + save_one_real_domain_aliases( Domain ); + } + /* did we want to save an alias of a particula domain? */ + else if ( Domain[0] > 0 && Alias[0] > 0 ) { + save_alias( Domain, Alias ); + } + /* save all aliases of all domains */ + else if ( SaveAll == 1 ) { + save_all_aliases(); + } + else { + usage(); + } + return(vexit(0)); +#endif +} + +void usage() +{ + printf("\nUsage: vsavealiasdomains [options] [real_domain] [alias_domain]\n"); + printf("options: -v (print version number)\n"); + printf(" -h (help)\n"); + printf(" -A (saves all aliases of all domains to MySQL)\n"); + printf("vsavealiasdomains domain (saves all aliases of a domain to MySQL)\n"); + printf("vsavealiasdomains real_domain alias_domain (saves an alias domain to MySQL)\n\n"); +} + +void get_options(int argc, char **argv) +{ + int c; + int errflag; + extern int optind; + + SaveAll = 0; + + memset(Domain, 0, sizeof(Domain)); + + errflag = 0; + while( !errflag && (c=getopt(argc,argv,"vAh")) != -1 ) { + switch(c) { + case 'v': + printf("version: %s\n", VERSION); + break; + + case 'A': + SaveAll = 1; + break; + + case 'h': + errflag = 1; + break; + + default: + errflag = 1; + break; + } + } + + if ( errflag > 0 ) { + usage(); + vexit(-1); + } + + if ( optind < argc ) { + snprintf(Domain, sizeof(Domain), "%s", argv[optind]); + ++optind; + } + + if ( optind < argc ) { + snprintf(Alias, sizeof(Alias), "%s", argv[optind]); + ++optind; + } + + if ( Domain[0]>0 && Alias[0]>0 && strcmp( Domain, Alias ) == 0 ) { + printf("Error: real domain and alias domain are the same!\n"); + usage(); + vexit(-1); + } +} + +#ifdef SQL_ALIASDOMAINS +/* + * Save all aliases of all real domains to database + */ +void save_all_aliases() +{ + domain_entry *entry; + entry = get_domain_entries(""); + + if (entry==NULL) { + if( verrori ) { + printf("Can't get domain entries - %s\n", verror( verrori )); + vexit(-1); + } else { + printf("No domain found\n"); + vexit(0); + } + } + + int i = 0; + while( entry ) { + /* we won't save realdomain/realdomain pairs */ + if ( strcmp(entry->realdomain,entry->domain) != 0 ) { + vcreate_sql_aliasdomain(entry->realdomain, entry->domain); + printf ("Alias: %s Real domain: %s saved\n", entry->domain, entry->realdomain); + ++i; + } + entry = get_domain_entries(NULL); + } + if ( i == 0 ) { + printf ("No aliases found\n"); + } +} + + +/* + * Save all aliases of domain Domain to database + */ +void save_one_real_domain_aliases( char *Domain ) +{ + domain_entry *entry; + entry = get_domain_entries ( Domain ); + + if (entry==NULL) { + if( verrori ) { + printf("Can't get domain entries - %s\n", verror( verrori )); + vexit(-1); + } else { + printf("%s does not exist\n", Domain); + vexit(0); + } + } + + int i = 0; + while( entry ) { + /* we won't save realdomain/realdomain pairs */ + if ( strcmp(entry->realdomain,entry->domain) != 0 ) { + vcreate_sql_aliasdomain(entry->realdomain, entry->domain); + printf ("Alias: %s Real domain: %s saved\n", entry->domain, entry->realdomain); + i++; + } + entry = get_domain_entries(NULL); + } + if ( i == 0 ) { + printf ("No aliases found for domain %s\n", Domain); + } +} + + +/* + * Save the pair Alias/Domain to database + */ +void save_alias( char *Domain, char *Alias ) +{ + domain_entry *entry; + entry = get_domain_entries ( Domain ); + + if (entry==NULL) { + if( verrori ) { + printf("Can't get domain entries - %s\n", verror( verrori )); + vexit(-1); + } else { + printf("%s does not exist\n", Domain); + vexit(0); + } + } + + int i = 0; + while( entry ) { + /* we won't save realdomain/realdomain pairs */ + if ( strcmp(Alias,entry->domain) == 0 && strcmp(entry->realdomain,entry->domain) != 0 ) { + vcreate_sql_aliasdomain(entry->realdomain, entry->domain); + printf ("Alias: %s Real domain: %s saved\n", entry->domain, entry->realdomain); + i++; + } + entry = get_domain_entries(NULL); + } + if ( i == 0 ) { + printf ("No alias %s found for domain %s\n", Alias, Domain); + } +} +#endif