+++ /dev/null
-diff -ur courier-imap-1.4.2.orig/authlib/README.authmysql.myownquery courier-imap-1.4.2/authlib/README.authmysql.myownquery
---- courier-imap-1.4.2.orig/authlib/README.authmysql.myownquery Tue Jan 8 06:01:22 2002
-+++ courier-imap-1.4.2/authlib/README.authmysql.myownquery Thu Feb 14 00:14:33 2002
-@@ -2,12 +2,13 @@
-
-
-
-- Developer Notes for courier-imap-myownquery.patch
-+ Developer Notes and Usage Instructions
-+ of courier-imap-authmysql-myownquery
-
-
-
-
-- document version: 1.03
-+ document version: 1.20
- author: Pawel Wilk
-
-
-@@ -24,57 +25,739 @@
-
-
-
-+PART I - Usage Instructions
-
--0 What's that?
-+ 1 What's that?
-+
-+ 2 When I'll need it?
-+
-+ 3 How does it work?
-+ 3.1 configuration variables
-+ 3.2 queries
-+ 3.3 substitutions
-+ 3.4 triggers
-+
-+ 4 Examples of usage
-+ 4.1 corporate mail system
-+ 4.1.1 database structure
-+ 4.1.2 authdaemon configuration
-+ 4.2 virtual mail domains provider
-+ 4.2.1 database structure
-+ 4.2.2 authdaemon configuration
-+
-+PART II - Developer Notes
-+
-+ 1 Modifications overview
-+
-+ 2 Definitions
-+
-+ 3 New data types
-+ 3.1 struct var_data
-+ 3.2 typedef size_t (*parsefunc)
-+
-+ 4 New functions
-+ 4.1 get_variable
-+ 4.2 parse_core
-+ 4.3 ParsePlugin_counter
-+ 4.4 ParsePlugin_builder
-+ 4.5 parse_string
-+ 4.6 validate_password
-+ 4.7 get_localpart
-+ 4.8 get_domain
-+ 4.9 get_username
-+ 4.10 parse_select_clause
-+ 4.11 parse_chpass_clause
-+ 4.12 auth_mysql_on_trigger
-
--1 Modifications overview
-+ 5 Ideas and TODO
-
--2 Definitions
-+ 6 Thanks
-
--3 New data types
-- 3.1 struct var_data
-- 3.2 typedef size_t (*parsefunc)
--
--4 New functions
-- 4.1 get_variable
-- 4.2 parse_core
-- 4.3 ParsePlugin_counter
-- 4.4 ParsePlugin_builder
-- 4.5 parse_string
-- 4.6 validate_password
-- 4.7 get_localpart
-- 4.8 get_domain
-- 4.9 parse_select_clause
-- 4.10 parse_chpass_clause
--
--5 Ideas and TODO
--
--6 Thanks
-
-
-
-+//////////////////////////////// PART I - Usage ///////////////////////////////
-
- *-----------------------
-- 0 What's that?
-+ 1 What's that?
- *-----------------------
-
--Courier-imap-myownquery.patch allows administrator to set own MySQL queries
--used by authdaemon to authenticate user (including fetchig credentials) and to
--change user's password. It allows to construct SELECT or UPDATE clause in the
--configuration file (authmysqlrc) by adding two new configuration variables:
--MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. It may be useful in the mail
--environments where there is such a need to have different database structure
--and/or tables scheme than expected by authmysql module.
-+Courier-imap-myownquery feature allows administrator to set his own MySQL
-+queries used by authdaemon to authenticate a user (including fetchig his
-+credentials) and to change the user's password. It allows to construct
-+SELECT and UPDATE clause in the configuration file (authmysqlrc) using
-+new configuration variables. It may be useful in the mail environments where
-+there is such a need to have different database structure and/or tables
-+scheme than expected by authmysql module.
-
- It also implements a small parsing engine for substitution variables which
--may appear in the clauses and are used to put informations like username
--or domain into the right place of a query.
-+may appear in the clauses and are used to put information like a username
-+or a domain into the right place within the query.
-
--This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
-
-
-
-
-+ *-----------------------
-+ 2 When I'll need it?
-+ *-----------------------
-+
-+ o When you already have some MySQL database filled up with the data
-+ and there is no chance to change the whole structure to make it
-+ working with standard authmysql table. Typical situation is when all the
-+ data required to authenticate a user is arranged in more than one table.
-+
-+ o When you have some great idea how to make the database structure
-+ more efficient due to your needs and your requirements.
-+
-+ o When doing something 'by-myself' is in your style and you just want
-+ to create your own database, just to feel the pleasure of doing
-+ something original. :)
-+
-+
-+
-+
-+
-+ *-----------------------
-+ 3 How does it work?
-+ *-----------------------
-+
-+There are three things which the feature concerns:
-+
-+- fetching clauses from the configuration file
-+- doing substitution replacements inside of clauses
-+- passing prepared query on to the mysql interface funtions
-+
-+3.1 configuration options
-+
-+You can apply your own MySQL queries using a set of the configuration options.
-+The options you'll need to make the authmysql your slave are:
-+
-+MYSQL_SERVER (required)
-+MYSQL_USERNAME (required)
-+MYSQL_PASSWORD (required)
-+
-+ The server name, userid, and password used to log in.
-+
-+MYSQL_DATABASE (required)
-+
-+ The name of the MySQL database we will open.
-+
-+DEFAULT_DOMAIN (optional)
-+
-+ If DEFAULT_DOMAIN is defined, and someone tries to log in as
-+ 'user', we will look up 'user@DEFAULT_DOMAIN' instead.
-+
-+USER_DOMAIN_CONCAT (optional)
-+
-+ The USER_DOMAIN_CONCAT defines a character(s) used to
-+ concatenate a local part and a domain while parsing
-+ the $(username) substitution variable (see section 3.3
-+ for more info). If it's not defined the @ sign is assumed.
-+
-+USER_DOMAIN_SEPARATORS (optional)
-+
-+ This may contain the set of characters used by parsing
-+ routines to split local part of the virtual mailbox name
-+ from the part which describes the domain name. If it's not
-+ defined the set containing @% is assumed, so the user can
-+ enter either: user@domain or user%domain when he wants to be
-+ authenticated.
-+
-+MYSQL_SELECT_CLAUSE (required)
-+MYSQL_CHPASS_CLAUSE (required under some circumstances)
-+
-+ These are the major options you should use. See 3.2 section
-+ for more info.
-+
-+MYSQL_ONSUCCESS_CLAUSE (optional)
-+MYSQL_ONFAIL_CLAUSE (optional)
-+
-+ These are used to do a MySQL query whether user has passed
-+ the authentication verification (MYSQL_ONSUCCESS_CLAUSE)
-+ or there was the authentication failure (MYSQL_ONFAIL_CLAUSE).
-+ Query results have no meaning. You can use the same
-+ substitution variables in your query as with
-+ MYSQL_SELECT_CLAUSE. See 3.4 section for more info.
-+
-+The options which have no effect, and may be safetly left blank are:
-+
-+MYSQL_USER_TABLE
-+MYSQL_CRYPT_PWFIELD
-+MYSQL_CLEAR_PWFIELD
-+MYSQL_UID_FIELD
-+MYSQL_GID_FIELD
-+MYSQL_LOGIN_FIELD
-+MYSQL_HOME_FIELD
-+MYSQL_NAME_FIELD
-+MYSQL_MAILDIR_FIELD
-+MYSQL_QUOTA_FIELD
-+MYSQL_WHERE_CLAUSE
-+
-+3.2 queries
-+
-+The feature adds two configuration options (clauses), which are parsed first,
-+and then applied as MySQL queries to MySQL interface routines. These options
-+are: MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. After each option a number of
-+spaces and/or tabs is allowed, and then MySQL query is expected. For better
-+look, your queries can have line breaks. Each line break should be preceded by
-+the backslash sign. Look into examples chapter (4) to see how it should look
-+like. First clause is used to authenticate a user, and the second to change his
-+password.
-+
-+You should note that a query identified by MYSQL_SELECT_CLAUSE should return
-+fixed number (9) of fields and each field should match the variable expected
-+by authentication routines. These fields are:
-+
-+* username - which is the currently logged user's username (or the
-+ username with domain if you want it)
-+
-+* cryptpw - which is the user's crypted password
-+
-+* clearpw - which is the user's plaintext password
-+
-+* uid - which is a numerical UID value used as a process's UID when
-+ accessing the mailbox directory
-+
-+* gid - as above, but refers to GID
-+
-+* home - which contains full path to the user's home directory
-+
-+maildir - which contains the directory name inside the user's home
-+ which is treated as INBOX folder when accessing mailbox
-+ - if it's empty then the 'Maildir' string is used
-+
-+quota - which describes a quota size for the mailbox
-+
-+fullname - which may contain the user's fullname
-+
-+(The fields marked by the asterix sign are required and cannot have an
-+ empty results)
-+
-+So, the typical query clause may start with:
-+
-+MYSQL_SELECT_CLAUSE SELECT \
-+ users.username, \
-+ users.cryptpw, \
-+ users.clearpw, \
-+ domains.uid, \
-+ domains.gid, \
-+ users.mailbox_path) \
-+ '' \
-+ domains.quota, \
-+ '' \
-+...
-+
-+Note that in this short example we're assuming that we have two tables
-+(users and domains) and INBOX path is always called 'Maildir' and
-+we're not using the fullname field (the query will always return an empty
-+string in its place).
-+
-+Also note that you may discard one of the password fields if you don't want
-+to use an authentication mechanism, which needs it. For example, if you don't
-+want to use MD5-CRAM you may put '' into the place of clearpw (because, for
-+example you're in paranoid mode and you don't even want to keep plain passwords
-+in the database:).
-+
-+3.3 substitutions
-+
-+Substitutions are strings, which may appear in your query, and which have a
-+special meaning. You can also call them substitution variables. If substitution
-+variable is known for a clause context then it is parsed. If it isn't known the
-+error is generated. In the default compilation of authmysql module any
-+substitution variable is declared inside of two substrings - the first is a
-+dollar sign concatenated with opening parenthesis, and the second is a closing
-+parenthesis sign. First symbol identifies beginning of a substitution variable,
-+and the second closes it. The string between the beginning and the closing
-+symbol is called substitution variable's name.
-+
-+When, as I said before, the name is known to the parsing routine the
-+substitution is made and the proper value appears in place of the substitution
-+variable, while passing on the query for later processing.
-+
-+Allowed substitution variables:
-+
-+context: MYSQL_SELECT_CLAUSE, MYSQL_ONFAIL_CLAUSE, MYSQL_ONSUCCESS_CLAUSE
-+
-+$(local_part) will be replaced by currently verified user's username
-+ (without the domain part)
-+
-+$(domain) will be replaced by currently verified user's domain
-+ name (if present, or if not present but the
-+ DEFAULT_DOMAIN was used) or by the empty, zero-length
-+ string if the domain cannot be obtained
-+
-+$(username) will be replaced by currently verified user's username
-+ concatenated with the given domain name using symbol
-+ defined by USER_DOMAIN_CONCAT - if the domiain name
-+ cannot be obtained (even by looking up DEFAULT_DOMAIN)
-+ the separation sign will not appear and only the given
-+ username will be presented
-+
-+context: MYSQL_CHPASS_CLAUSE
-+
-+$(local_part) will be replaced by currently verified user's username
-+ (without the domain part)
-+
-+$(domain) will be replaced by currently verified user's domain
-+ name (if present, or if not present but the
-+ DEFAULT_DOMAIN was used) or by the empty, zero-length
-+ string if the domain cannot be obtained
-+
-+$(username) will be replaced by currently verified user's username
-+ concatenated with the given domain name using symbol
-+ defined by USER_DOMAIN_CONCAT - if the domiain name
-+ cannot be obtained (even by looking up DEFAULT_DOMAIN)
-+ the separation sign will not appear and only the given
-+ username will be presented
-+
-+$(newpass) will be replaced by currently authenticated user's
-+ new password to set up (plaintext password)
-+
-+$(newpass_crypt) will be replaced by currently authenticated user's
-+ new password to set up (MD5 form created from entered
-+ plain form)
-+
-+3.4 triggers
-+
-+Triggers are MySQL queries, which are performed depending on authentication
-+state. Currently, there are two triggers which you may use. First is called
-+MYSQL_ONSUCCESS_CLAUSE and it is performed when the authentication succeedes.
-+The second is called MYSQL_ONFAIL_CLAUSE and has the reverse meaning. You can
-+declare triggers in the authmysqlrc configuration file. They can be used to
-+arrange some logging facility in the database or just to keep last times
-+of the successful/failed login tries. The typical trigger, which puts last
-+login date into the users' table can look like this:
-+
-+MYSQL_ONSUCCESS_CLAUSE UPDATE users SET last_login=CURRENT_TIMESTAMP \
-+ WHERE username='$(username)';
-+
-+or, if you would like to know about last login failure for users you can try:
-+
-+MYSQL_ONFAIL_CLAUSE UPDATE users SET last_bad_login=CURRENT_TIMESTAMP \
-+ WHERE username='$(username)';
-+
-+Note, that YOU CAN use the triggers even if you aren't using
-+MYSQL_SELECT_CLAUSE. Also note, that there is such a possibility that ONFAIL
-+trigger may be performed without a proper username. Take it into consideration
-+when creating queries to avoid messy data on INSERT operations.
-+
-+
-+
-+
-+
-+
-+ *-----------------------
-+ 4 Examples of usage
-+ *-----------------------
-+
-+The "ownquery" feature gives you possibility to adapt an authentication query
-+to the database. So the first thing you have to do is to design the database
-+structure you need, whithout being grieved at what structure authentication
-+routines like. You have to take care about four essential things:
-+
-+ o The database
-+
-+ o The users' data in the database
-+
-+ o The proper directories for keeping virtual mailboxes and a system user
-+ which can read and write them
-+
-+ o The proper MySQL queries in your authmysqlrc configuration file
-+
-+4.1 corporate mail system
-+
-+This example is concerned about a corporate mail system with a small
-+count of served virtual domains. The database scheme was derived from tpop3d
-+documentation and modified a bit.
-+
-+4.1.1 database structure
-+
-+Our goal here is to separate the data responsible for keeping mailbox
-+credentials from the data, which describes a domain.
-+
-+Let's create some tables for our example, filled up with an example data:
-+
-+table: domains
-+
-+purpose: associates virtual domain with domain name and informations
-+ necessary to access mailboxes withing the domain
-+
-+fields: domain_name - fully qualified domain name
-+ path_prefix - absolute pathname which points to
-+ a directory where domain's mailboxes
-+ are located
-+ quota - default quota for each mailbox
-+ uid - UID used to work on mailboxes
-+ gid - GID used to work on mailboxes
-+
-+ +----------------+-------------+-----+-----+----------+
-+ | domain_name | path_prefix | uid | gid | quota |
-+ +----------------+-------------+-----+-----+----------+
-+ | exampledom.com | /var/mail/x | 555 | 555 | 10000000 |
-+ | pld.org.pl | /var/mail/p | 556 | 556 | 20000000 |
-+ | pld.net.pl | /var/mail/p | 556 | 556 | 20000000 |
-+ +----------------+-------------+-----+-----+----------+
-+
-+table: users
-+
-+purpose: associates virtual mailbox with user and domain name,
-+ and with informations necessary to access mailbox
-+
-+fields: username - user login name (mailbox name)
-+ domain_name - fully qualified domain name
-+ mailbox_path - relative pathname for mailbox
-+ (will be appended to the path_prefix
-+ from domain_auth table to specify
-+ user's mailbox location)
-+ cryptpw - crypted password
-+ plainpw - plaintext password
-+
-+ +----------+----------------+--------------+------------+--------+
-+ | username | domain_name | mailbox_path | cryptpw | plainpw |
-+ +----------+----------------+--------------+-----------+---------+
-+ | siefca | pld.org.pl | s/siefca | $1$fs45.. | dupa.8 |
-+ | siefca | pld.net.pl | s/siefca | $1$fs45.. | dupa.8 |
-+ | f00bar | exampledom.com | foobar | $1$g44w.. | secret |
-+ +----------+----------------+--------------+-----------+---------+
-+
-+Using MySQL monitor you can create these tables entering CREATE sequences.
-+Be sure to connect to the database using administrative MySQL account
-+(usualy: mysql -u mysql -p).
-+
-+--------------------- cut here
-+
-+# Create the database called vmail.
-+
-+CREATE database vmail;
-+
-+# Create an example MySQL user, which can read, write and delete data from
-+# vmail database. Username: vuser Password: secret_password
-+
-+GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
-+ TO vuser@localhost
-+ IDENTIFIED BY 'secret_password';
-+
-+FLUSH PRIVILEGES;
-+
-+# Create the tables.
-+
-+use vmail;
-+
-+CREATE TABLE domains (
-+ domain_name char(255) DEFAULT '',
-+ path_prefix char(255) DEFAULT '' NOT NULL,
-+ uid int(10) unsigned DEFAULT '15000' NOT NULL,
-+ gid int(10) unsigned DEFAULT '15000' NOT NULL,
-+ quota char(255) DEFAULT '2000000' NOT NULL,
-+ KEY domain_name (domain_name(255))
-+ );
-+
-+CREATE TABLE users (
-+ username char(128) DEFAULT '' NOT NULL,
-+ domain_name char(255) DEFAULT '',
-+ mailbox_path char(255) DEFAULT '' NOT NULL,
-+ cryptpw char(128) DEFAULT '' NOT NULL,
-+ clearpw char(128) DEFAULT '' NOT NULL,
-+ KEY username (username(128))
-+ );
-+
-+# Create an example virtual domain entry
-+# name : exampledom.com
-+# uid : 555
-+# gid : 555
-+# path : /var/mail/x
-+# quota : 10 Megs per mailbox
-+
-+INSERT INTO domains VALUES ('exampledom.com', '/var/mail/x', 555, 555,
-+ '10000000');
-+
-+# Create an example virtual user entry
-+# username : siefca
-+# domain name : exampledom.com
-+# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
-+# clearpw : dupa.8
-+# mailbox path : s/siefca
-+
-+INSERT INTO users VALUES ('siefca', 'exampledom.com', 's/siefca',
-+ '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
-+ 'dupa.8');
-+
-+--------------------- cut here
-+
-+Note: If you would like to have your passwords more safe then just omit the
-+ clearpw column and put '' into the config-query in its place while
-+ doing SELECT on a database. But be ware - you'll be unable to use
-+ authentication methods which needs it, like MD5_CRAM.
-+
-+4.1.2 authdaemon configuration
-+
-+When our database is ready we can set up the configuration. :-) Go to
-+authmysqlrc file and edit it.
-+
-+At the beginning we should take care about general informations, which
-+are identifying our database:
-+
-+MYSQL_SERVER localhost
-+MYSQL_USERNAME vuser
-+MYSQL_PASSWORD secret_password
-+MYSQL_DATABASE vmail
-+
-+Then we should add a clause responsible for authenticating user and
-+fetching credentials:
-+
-+DEFAULT_DOMAIN exampledom.com
-+
-+MYSQL_SELECT_CLAUSE SELECT \
-+ users.username, users.cryptpw, users.clearpw, \
-+ domains.uid, domains.gid, \
-+ CONCAT_WS('/',domains.path_prefix,users.mailbox_path), \
-+ '', domains.quota, '' \
-+ FROM users, domains \
-+ WHERE domains.domain_name='$(domain)' \
-+ AND users.username='$(local_part)' \
-+ AND domains.domain_name=users.domain_name
-+
-+
-+Note the '' in the place of field which tells where user's INBOX resides
-+and in place of realname field. You should use '' if you want to put an empty
-+value as a query result for some field.
-+
-+We also should add some configuration for changing user's password:
-+
-+MYSQL_CHPASS_CLAUSE UPDATE \
-+ users \
-+ SET clearpw='$(newpass)', \
-+ cryptpw='$(newpass_crypt)' \
-+ WHERE username='$(local_part)' \
-+ AND domain_name='$(domain)'
-+
-+Last things to have sure...
-+Create a system user/group and a proper directory structure. In our example:
-+
-+groupadd -g 555 xdomain
-+useradd -u 555 -g 555 xdomain
-+mkdir -p /var/mail/x/s/siefca
-+chmod -R 0770 /var/mail/x
-+maildirmake /var/mail/x/s/siefca/Maildir
-+chown -R xdomain.xdomain /var/mail/x
-+
-+Now, restart the authdaemon and see if it works. Try: telnet 0 pop3
-+
-+and type:
-+
-+USER siefca [ENTER]
-+PASS dupa.8 [ENTER]
-+
-+You should get Ok response. ;)
-+
-+4.2 virtual mail domains provider
-+
-+Let's consider more complicated database scheme, where is a need to
-+associate a lot of information with the domain name, including registrant
-+information, owner, etc. That implies data separation between domain name,
-+user and domain additional informations (which are unwanted when
-+authentication process takes place). By the proper data separation I mean
-+avoiding unwanted redundancy in the database.
-+
-+Currently applied example doesn't care about the update password problem.
-+This is due to current abilities of MySQL and authdaemon (authmysql).
-+MySQL doesn't support subsequent SELECTs on UPDATE operation, and authmysql
-+doesn't supports batched queries at the moment.
-+
-+4.2.1 database structure
-+
-+table: domain_names
-+
-+purpose: associates domain_id with domain name
-+
-+fields: domain_name - fully qualified domain name
-+ domain_id - domain identifier
-+
-+ +----------------+-----------+
-+ | domain_name | domain_id |
-+ +----------------+-----------+
-+ | exampledom.com | 1 |
-+ | pld.org.pl | 2 |
-+ | pld.net.pl | 2 |
-+ | foobare.net.uk | 3 |
-+ +----------------+-----------+
-+
-+Note, that for pld.org.pl and pld.net.pl the domain identifiers are the same.
-+We can create a domain aliases in such a way. :)
-+
-+table: domain_auth
-+
-+purpose: associates domain_id with authentication credentials
-+ which are common for all users in the virtual domain
-+
-+fields: domain_id - domain identifier
-+ path_prefix - absolute pathname which points to
-+ a directory where domain's mailboxes
-+ are located
-+ quota - default quota for each mailbox
-+ uid - UID used to work on mailboxes
-+ gid - GID used to work on mailboxes
-+
-+ +------------+---------------+--------+-------+-------+
-+ | domain_id | path_prefix | quota | uid | gid |
-+ +------------+---------------+--------+-------+-------+
-+ | 1 | /var/mail/ex | 100000 | 15000 | 15000 |
-+ | 2 | /var/mail/pld | 555500 | 15001 | 15000 |
-+ | 3 | /home/f0/mail | 8000 | 15002 | 15000 |
-+ +------------+---------------+--------+-------+-------+
-+
-+table: domain_info
-+
-+purpose: associates domain_id with additional informations
-+
-+fields: domain_id - domain identifier
-+ registrant_id - registrant identifier
-+ nic_handle - NIC handle
-+ owner_id - domain's owner identifier
-+ expires - domain's expiration date
-+
-+ +------------+---------------+------------+----------+---------+
-+ | domain_id | registrant_id | nic_handle | owner_id | expires |
-+ +------------+---------------+------------+----------+---------+
-+
-+ (we don't need to say anything more about this table indeed)
-+
-+table: users
-+
-+purpose: associates users' identifiers with domains' identifiers
-+ and infers the credentials for various virtual mailboxes
-+
-+fields: username - user's login name
-+ domain_id - domain identifier
-+ cryptpw - crypted password
-+ plainpw - plaintext password
-+ quota - user's mailbox quota
-+ (will override quota value set for
-+ the whole virtual domain)
-+ path - relative pathname for mailbox
-+ (will be appended to the path_prefix
-+ from domain_auth table to specify
-+ user's mailbox location)
-+
-+ +------------+-----------+----------+-----------+-------+------------+
-+ | username | domain_id | cryptpw | plainpw | quota | path |
-+ +------------+-----------+----------+-----------+-------+------------+
-+ | foobar | 1 | $1$hlIeE | dupa.8 | NULL | f/o/foobar |
-+ | breeder | 2 | $1$TWsdf | ziarno128 | 77777 | brd |
-+ +------------+-----------+----------+-----------+-------+------------+
-+
-+ (you can add a realname column here, it doesn't fit to my terminal window:)
-+
-+--------------------- cut here
-+
-+# Create the database called vmail.
-+
-+CREATE database vmail;
-+
-+# Create an example MySQL user, which can read, write and delete data from
-+# vmail database. Username: vuser Password: secret_password
-+
-+GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
-+ TO vuser@localhost
-+ IDENTIFIED BY 'secret_password';
-+
-+FLUSH PRIVILEGES;
-+
-+# Create the tables.
-+
-+use vmail;
-+
-+CREATE TABLE domain_names (
-+ domain_id int(10) unsigned NOT NULL,
-+ domain_name char(255) DEFAULT '' NOT NULL,
-+ KEY domain_name (domain_name(255))
-+ );
-+
-+CREATE TABLE domain_auth (
-+ domain_id int(10) unsigned DEFAULT 1 NOT NULL,
-+ uid int(10) unsigned DEFAULT '15000' NOT NULL,
-+ gid int(10) unsigned DEFAULT '15000' NOT NULL,
-+ path_prefix char(255) DEFAULT '' NOT NULL,
-+ quota char(255) DEFAULT '20000000' NOT NULL,
-+ KEY domain_id (domain_id)
-+ );
-+
-+CREATE TABLE users (
-+ username char(128) DEFAULT '' NOT NULL,
-+ domain_id int(10) unsigned DEFAULT 1 NOT NULL,
-+ cryptpw char(128) DEFAULT '' NOT NULL,
-+ plainpw char(128) DEFAULT '' NOT NULL,
-+ name char(128) DEFAULT '' NOT NULL,
-+ quota char(255),
-+ path char(255) DEFAULT '' NOT NULL,
-+ KEY username (username(128))
-+ );
-+
-+# Create an example virtual domain entry
-+# id : 1
-+# name : exampledom.com
-+# uid : 15000
-+# gid : 15000
-+# path : /var/mail/example
-+# quota : 20 Megs per mailbox
-+
-+INSERT INTO domain_names VALUES (1, 'exampledom.com');
-+INSERT INTO domain_auth VALUES (1, '15000', '15000', '/var/mail/example',
-+ '20000000');
-+
-+# Create an example virtual user entry
-+# username : siefca
-+# domain id : 1 (points to exampledom.com)
-+# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
-+# clearpw : dupa.8
-+# name : Pawel Wilk
-+# quota : NULL (we want it to be fetched from domain_auth table)
-+# mailbox path : s/i/siefca
-+
-+INSERT INTO users VALUES ('siefca', 1, '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
-+ 'dupa.8', 'Pawel Wilk', NULL, 's/i/siefca');
-+
-+--------------------- cut here
-+
-+Ok, we've done what we need. Don't forget to create system user with UID and
-+GID set to 15000, and a directory containing mailboxes (in this case:
-+/var/mail/example) owned by system user I've mentioned above.
-+There is also necessary to create Maildir folder structure for our user
-+inside the virtual domain directory - you can configure your MTA agent to do
-+such thing when first message arrive or use maildirmake tool, which comes
-+with Courier-IMAP.
-+
-+
-+4.2.2 authdaemon configuration
-+
-+DEFAULT_DOMAIN exampledom.com
-+
-+MYSQL_SELECT_CLAUSE SELECT \
-+ users.username, \
-+ users.cryptpw, \
-+ users.plainpw, \
-+ domain_auth.uid, \
-+ domain_auth.gid, \
-+ CONCAT_WS('/',domain_auth.path_prefix,users.path), \
-+ '', \
-+ IFNULL(users.quota, domain_auth.quota), \
-+ users.name \
-+ FROM users, domain_names, domain_auth \
-+ WHERE domain_names.domain_name='$(domain)' \
-+ AND users.username='$(local_part)' \
-+ AND domain_names.domain_id=users.domain_id \
-+ AND domain_names.domain_id=domain_auth.domain_id
-+
-+
-+.
-+.
-+.
-+.
-+.
-+.
-+
-+/////////////////////////// PART II - Developer Notes /////////////////////////
-
- *-----------------------
- 1 Modifications overview
-@@ -85,7 +768,7 @@
- Each modified set of instructions is marked by my e-mail address:
- siefca@pld.org.pl
-
--Changes in the current source code are related to:
-+Changes in the source code are related to:
-
- - sections where the queries are constructed
- (including memory allocation for the buffers)
-@@ -102,6 +785,10 @@
- newline as the second is replaced by two whitespaces while
- putting into the buffer
-
-+ i've also added USER_DOMAIN_CONCAT and USER_DOMAIN_SEPARATORS
-+ configuration options - they're used by get_localpart(), get_domain()
-+ and get_username() functions, which are described below
-+
- - sections where the query is constructed
-
- selection is made, depending on configuration variables which
-@@ -130,7 +817,16 @@
- MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
- identifier (name).
-
--The last two definitions are just for code simplification.
-+The last two definitions (SV_BEGIN_LEN and SV_END_LEN) are just for code
-+simplification.
-+
-+#define DEF_CONCAT_STRING "@"
-+#define DEF_SEPARATORS_SET "@%"
-+
-+The first (DEF_CONCAT_STRING) is used to set the defaults for a
-+concatenation string, used when parsing $(username) substitution variable.
-+The second (DEF_SEPARATORS_SET) is the set of characters, which are treated as
-+separators when splitting local part from the domain.
-
-
-
-@@ -179,7 +875,7 @@
- In this example we've declared that $(some) in the query should be
- replaced by 'replacement' text, and replacement for $(anotha) will
- be defined in the code before passing on the array pointer to
--the paring function.
-+the general parsing function.
-
-
- 3.2 typedef size_t (*parsefunc)
-@@ -414,14 +1110,17 @@
-
- SYNOPSIS
-
-- static const char *get_localpart (const char *username);
-+ static const char *get_localpart (const char *username,
-+ const char *separators);
-
- DESCRIPTION
-
- This function detaches local part of an e-mail address
- from string pointed with username and puts it to the
- buffer of the fixed length. All necessary cleaning is
-- made on the result string.
-+ made on the result string. String pointed with separators
-+ refers to a set of characters, which are treated as
-+ separation signs between local part and a domain.
-
- RETURN VALUE
-
-@@ -438,16 +1137,22 @@
- SYNOPSIS
-
- static const char *get_domain (const char *username,
-- const char *defdomain);
-+ const char *defdomain,
-+ const char *separators);
-
- DESCRIPTION
-
- This function detaches domain part of an e-mail address
- from string pointed with username and puts it to the
- buffer of the fixed length. All necessary cleaning is
-- made on the result string. If function cannot find domain
-- part in the string the string pointed by defdomain is
-- used instead.
-+ made on the result string. If the function cannot find a domain
-+ part in the string then the string pointed to by defdomain is
-+ used instead. If this function cannot find a domain part
-+ as well as it cannot obtain the default domain (it's empty string
-+ or the defdomain pointer is NULL) the returned result string is an
-+ empty string. The string pointed with separators refers to a set
-+ of characters, which are treated as separation signs between local
-+ part and a domain.
-
- RETURN VALUE
-
-@@ -455,7 +1160,36 @@
- NULL if there was some error.
-
-
--4.9 parse_select_clause
-+4.9 get_username
-+
-+NAME
-+
-+ get_username
-+
-+SYNOPSIS
-+
-+ static const char *get_username (const char *username,
-+ const char *domainname,
-+ const char *concat_str);
-+
-+DESCRIPTION
-+
-+ This function concatenates the localpart with a domain name
-+ using the string pointed with concat_str. If the domain is
-+ empty or NULL the result comes without binding string.
-+
-+RETURN VALUE
-+
-+ Pointer to the static buffer containing output string or
-+ NULL if there was some error.
-+
-+WARNINGS
-+
-+ This function does not any string cleaning, nor default domain
-+ checking. It is designed to work on results of get_localpart() and
-+ get_domain().
-+
-+4.10 parse_select_clause
-
- NAME
-
-@@ -465,7 +1199,9 @@
-
- static char *parse_select_clause (const char *clause,
- const char *username,
-- const char *defdomain);
-+ const char *defdomain
-+ const char *concat_str,
-+ const char *separators_set);
-
- DESCRIPTION
-
-@@ -473,15 +1209,17 @@
- function. It parses a query pointed by caluse. username
- and defdomain strings are used to replace corresponding
- substitution strings if present in the query: $(local_part)
-- and $(domain).
-+ and $(domain). The separators_set is passed to get_username()
-+ and get_domain() invocations, and the concat_str is passed
-+ to get_username() function, which is responsible for replacing
-+ $(username) substitution variable.
-
--
- RETURN VALUE
-
- Same as parse_string().
-
-
--4.10 parse_chpass_clause
-+4.11 parse_chpass_clause
-
- NAME
-
-@@ -492,6 +1230,8 @@
- static char *parse_chpass_clause (const char *clause,
- const char *username,
- const char *defdomain,
-+ const char *separators_set,
-+ const char *concat_str,
- const char *newpass,
- const char *newpass_crypt);
-
-@@ -502,12 +1242,47 @@
- defdomain, newpass and newpass_crypt strings are used to
- replace corresponding substitution strings if present in
- the query: $(local_part), $(domain), $(newpass),
-- $(newpass_crypt).
-+ $(newpass_crypt). The separators_set and the concat_str
-+ are passed to get_localpart(), get_domain(), and get_username()
-+ functions as described in the entry for parse_select_clause().
-
- RETURN VALUE
-
- Same as parse_string().
-
-+4.12 auth_mysql_on_trigger
-+
-+NAME
-+
-+ auth_mysql_on_trigger
-+
-+SYNOPSIS
-+
-+ int auth_mysql_on_trigger (const char *clause_name,
-+ const char *username);
-+
-+DESCRIPTION
-+
-+ This function is responsible for calling out the MySQL queries in
-+ depend which authentication state was reached.
-+
-+ The clause_name should contain the name of a clause, which can be found
-+ in the configuration file, and the username is simply the string used
-+ as username (including the domain if entered).
-+
-+ This function reads DEFAULT_DOMAIN, USER_DOMAIN_CONCAT and
-+ USER_DOMAIN_SEPARATORS from the configuration file using read_env(),
-+ then it uses parse_select_clause() to parse the query obtained using
-+ read_env(clause_name), and then it calls querying subroutines to
-+ perform the action.
-+
-+RETURN VALUE
-+
-+ This function returns 1 on success and 0 on failure. The query results
-+ are simply discarded. If a trigger's clause is not defined in the
-+ configuration file the 1 is returned and function silently ends its
-+ work.
-+
-
-
-
-@@ -520,11 +1295,9 @@
- strings after split (problem?)
- - allow admin to set a group name instead of numerical group id
- - allow admin to set a username instead of numerical user id
--
--- add clauses:
--
-- - MYSQL_PRESELECT_CLAUSE (query which comes before MYSQL_SELECT_CLAUSE)
-- - MYSQL_POSTSELECT_CLAUSE (query which comes after MYSQL_SELECT_CLAUSE)
-+- allow batched queries and register variables for keeping results
-+- put the parsing routines into separate files to make possible of sharing it
-+ by more authentication modules
-
-
-
-@@ -534,10 +1307,12 @@
- 6 Thanks
- *------------------------
-
--At the beginning this patch was messy indeed. :> I would like to thank
-+At the beginning the patch was messy indeed. :> I would like to thank
- Sam Varshavchik for pointing me a lot how to make it more fast and solid.
- I would also thank Philip Hazel, Chris Lightfoot and Mike Bremford which
--by their software capabilities inspired me to write it.
-+by their software capabilities inspired me to write it. Oliver Oblasnik
-+remainded me to make the documentation more friendly for those who are
-+not programmers and just want to use it. :>
-
- ---------------------------------------------------------------------------
-
-diff -ur courier-imap-1.4.2.orig/authlib/authmysql.c courier-imap-1.4.2/authlib/authmysql.c
---- courier-imap-1.4.2.orig/authlib/authmysql.c Sun Jun 24 01:42:05 2001
-+++ courier-imap-1.4.2/authlib/authmysql.c Sun Feb 10 04:54:37 2002
-@@ -31,7 +31,11 @@
- if ((user=strtok(authdata, "\n")) == 0 ||
- (pass=strtok(0, "\n")) == 0)
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0);
- }
-
-@@ -50,7 +54,11 @@
- {
- if (authcheckpassword(pass,authinfo->cryptpw))
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0); /* User/Password not found. */
- }
- }
-@@ -58,13 +66,21 @@
- {
- if (strcmp(pass, authinfo->clearpw))
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0);
- }
- }
- else
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0); /* Username not found */
- }
-
-@@ -132,6 +148,12 @@
- (*callback_func)(&aa, callback_arg);
- }
-
-+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
-+ {
-+ errno=EACCES;
-+ return (0);
-+ }
-+
- return (strdup(authinfo->username));
- }
-
-@@ -153,7 +175,11 @@
- {
- if (authcheckpassword(pass,authinfo->cryptpw))
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (-1); /* User/Password not found. */
- }
- }
-@@ -161,13 +187,21 @@
- {
- if (strcmp(pass, authinfo->clearpw))
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (-1);
- }
- }
- else
- {
-- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (-1);
- }
-
-@@ -176,6 +210,13 @@
- errno=EPERM;
- return (-1);
- }
-+
-+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
-+ {
-+ errno=EACCES;
-+ return (-1);
-+ }
-+
- return (0);
- }
-
-diff -ur courier-imap-1.4.2.orig/authlib/authmysql.h courier-imap-1.4.2/authlib/authmysql.h
---- courier-imap-1.4.2.orig/authlib/authmysql.h Mon Aug 6 05:12:39 2001
-+++ courier-imap-1.4.2/authlib/authmysql.h Sun Feb 10 04:56:30 2002
-@@ -21,6 +21,7 @@
- } ;
-
- extern struct authmysqluserinfo *auth_mysql_getuserinfo(const char *);
-+extern int auth_mysql_on_trigger (const char *clause_name, const char *username);
- extern void auth_mysql_cleanup();
-
- extern int auth_mysql_setpass(const char *, const char *);
-diff -ur courier-imap-1.4.2.orig/authlib/authmysqllib.c courier-imap-1.4.2/authlib/authmysqllib.c
---- courier-imap-1.4.2.orig/authlib/authmysqllib.c Thu Jan 10 05:44:06 2002
-+++ courier-imap-1.4.2/authlib/authmysqllib.c Sun Feb 10 14:35:10 2002
-@@ -24,6 +24,9 @@
- #define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
- #define SV_END_LEN ((sizeof(SV_END_MARK))-1)
-
-+#define DEF_CONCAT_STRING "@"
-+#define DEF_SEPARATORS_SET "@%"
-+
- static const char rcsid[]="$Id$";
-
- /* siefca@pld.org.pl */
-@@ -426,21 +429,43 @@
- return NULL;
- }
- *pass_buf = '\0';
--
-+
- return output_buf;
- }
-
- /* siefca@pld.org.pl */
--static const char *get_localpart (const char *username)
-+static const char *get_username (const char *username, const char *domainname,
-+ const char *concat_str)
-+{
-+static char username_buf[400];
-+
-+ if (!username || !domainname || !concat_str ||
-+ *username == '\0' || *concat_str == '\0') return NULL;
-+ if (( strlen(username) +
-+ strlen(concat_str) +
-+ strlen(domainname)) > 397) return NULL;
-+
-+ if (*domainname == '\0')
-+ strcpy (username_buf, username);
-+ else
-+ sprintf (username_buf, "%s%s%s", username, concat_str,
-+ domainname);
-+
-+ return (username_buf);
-+}
-+
-+/* siefca@pld.org.pl */
-+static const char *get_localpart (const char *username, const char *separators)
- {
- size_t lbuf = 0;
- const char *l_end, *p;
- char *q;
- static char localpart_buf[130];
-
-- if (!username || *username == '\0') return NULL;
-+ if (!username || *username == '\0' ||
-+ !separators || *separators == '\0') return NULL;
-
-- p = strchr(username,'@');
-+ p = strpbrk (username, separators);
- if (p)
- {
- if ((p-username) > 128)
-@@ -469,21 +494,27 @@
- }
-
- /* siefca@pld.org.pl */
--static const char *get_domain (const char *username, const char *defdomain)
-+static const char *get_domain (const char *username, const char *defdomain,
-+ const char *separators)
- {
- static char domain_buf[260];
- const char *p;
- char *q;
-
-- if (!username || *username == '\0') return NULL;
-- p = strchr(username,'@');
-+ if (!username || *username == '\0' ||
-+ !separators || *separators == '\0') return NULL;
-+
-+ p = strpbrk (username, separators);
-
- if (!p || *(p+1) == '\0')
- {
-- if (defdomain && *defdomain)
-+ if (defdomain && *defdomain != '\0')
- return defdomain;
- else
-- return NULL;
-+ {
-+ *domain_buf = '\0';
-+ return domain_buf;
-+ }
- }
-
- p++;
-@@ -528,20 +559,27 @@
-
- /* siefca@pld.org.pl */
- static char *parse_select_clause (const char *clause, const char *username,
-- const char *defdomain)
-+ const char *defdomain,
-+ const char *concat_str,
-+ const char *separators_set)
- {
- static struct var_data vd[]={
- {"local_part", NULL, sizeof("local_part"), 0},
- {"domain", NULL, sizeof("domain"), 0},
-+ {"username", NULL, sizeof("username"), 0},
- {NULL, NULL, 0, 0}};
-
- if (clause == NULL || *clause == '\0' ||
-- !username || *username == '\0')
-+ !username || *username == '\0' ||
-+ !concat_str || *concat_str == '\0' ||
-+ !separators_set || *separators_set == '\0')
- return NULL;
-
-- vd[0].value = get_localpart (username);
-- vd[1].value = get_domain (username, defdomain);
-- if (!vd[0].value || !vd[1].value)
-+ vd[0].value = get_localpart (username, separators_set);
-+ vd[1].value = get_domain (username, defdomain, separators_set);
-+ vd[2].value = get_username (vd[0].value, vd[1].value, concat_str);
-+
-+ if (!vd[0].value || !vd[1].value || !vd[2].value)
- return NULL;
-
- return (parse_string (clause, vd));
-@@ -549,12 +587,16 @@
-
- /* siefca@pld.org.pl */
- static char *parse_chpass_clause (const char *clause, const char *username,
-- const char *defdomain, const char *newpass,
-+ const char *defdomain,
-+ const char *separators_set,
-+ const char *concat_str,
-+ const char *newpass,
- const char *newpass_crypt)
- {
- static struct var_data vd[]={
- {"local_part", NULL, sizeof("local_part"), 0},
- {"domain", NULL, sizeof("domain"), 0},
-+ {"username", NULL, sizeof("username"), 0},
- {"newpass", NULL, sizeof("newpass"), 0},
- {"newpass_crypt", NULL, sizeof("newpass_crypt"), 0},
- {NULL, NULL, 0, 0}};
-@@ -562,19 +604,83 @@
- if (clause == NULL || *clause == '\0' ||
- !username || *username == '\0' ||
- !newpass || *newpass == '\0' ||
-+ !separators_set || *separators_set == '\0' ||
- !newpass_crypt || *newpass_crypt == '\0') return NULL;
-
-- vd[0].value = get_localpart (username);
-- vd[1].value = get_domain (username, defdomain);
-- vd[2].value = validate_password (newpass);
-- vd[3].value = validate_password (newpass_crypt);
-+ vd[0].value = get_localpart (username, separators_set);
-+ vd[1].value = get_domain (username, defdomain, separators_set);
-+ vd[3].value = get_username (vd[0].value, vd[1].value, concat_str);
-+ vd[4].value = validate_password (newpass);
-+ vd[5].value = validate_password (newpass_crypt);
-
- if (!vd[0].value || !vd[1].value ||
-- !vd[2].value || !vd[3].value) return NULL;
-+ !vd[2].value || !vd[3].value ||
-+ !vd[4].value || !vd[5].value) return NULL;
-
- return (parse_string (clause, vd));
- }
-
-+/* siefca@pld.org.pl */
-+int auth_mysql_on_trigger (const char *clause_name, const char *username)
-+{
-+char *querybuf =NULL;
-+const char *concat_str =NULL,
-+ *separators_set =NULL,
-+ *defdomain =NULL,
-+ *on_clause =NULL;
-+MYSQL_RES *result;
-+
-+ if (!clause_name || *clause_name == '\0') return (0);
-+ on_clause = read_env (clause_name);
-+ if (!on_clause || *on_clause == '\0') return (1);
-+
-+ defdomain = read_env ("DEFAULT_DOMAIN");
-+ concat_str = read_env ("USER_DOMAIN_CONCAT");
-+ separators_set = read_env ("USER_DOMAIN_SEPARATORS");
-+ if (!defdomain) defdomain = "";
-+ if (!concat_str || *concat_str == '\0')
-+ concat_str = DEF_CONCAT_STRING;
-+ if (!separators_set || *separators_set == '\0')
-+ separators_set = DEF_SEPARATORS_SET;
-+
-+ querybuf = parse_select_clause (on_clause,
-+ username,
-+ defdomain,
-+ concat_str,
-+ separators_set);
-+
-+ if (!querybuf) return (0);
-+
-+ if (mysql_query (mysql, querybuf))
-+ {
-+ /* <o.blasnik@nextra.de> */
-+
-+ auth_mysql_cleanup();
-+
-+ if (do_connect())
-+ {
-+ free(querybuf);
-+ return (1);
-+ }
-+
-+ if (mysql_query (mysql, querybuf))
-+ {
-+ free(querybuf);
-+ auth_mysql_cleanup();
-+ /* Server went down, that's OK,
-+ ** try again next time.
-+ */
-+ return (1);
-+ }
-+ }
-+ free(querybuf);
-+ result = mysql_store_result(mysql);
-+ if (result) mysql_free_result(result);
-+
-+ return (1);
-+}
-+
-+
- struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username)
- {
- const char *user_table =NULL;
-@@ -593,6 +699,8 @@
- *gid_field =NULL,
- *quota_field =NULL,
- *where_clause =NULL,
-+ *concat_str =NULL,
-+ *separators_set =NULL,
- *select_clause =NULL; /* siefca@pld.org.pl */
-
- static const char query[]=
-@@ -701,7 +809,19 @@
- else
- {
- /* siefca@pld.org.pl */
-- querybuf=parse_select_clause (select_clause, username, defdomain);
-+ concat_str = read_env ("USER_DOMAIN_CONCAT");
-+ separators_set = read_env ("USER_DOMAIN_SEPARATORS");
-+
-+ if (!concat_str || *concat_str == '\0')
-+ concat_str = DEF_CONCAT_STRING;
-+ if (!separators_set || *separators_set == '\0')
-+ separators_set = DEF_SEPARATORS_SET;
-+
-+ querybuf = parse_select_clause (select_clause,
-+ username,
-+ defdomain,
-+ concat_str,
-+ separators_set);
- if (!querybuf) return 0;
- }
-
-@@ -785,6 +905,8 @@
- *where_clause =NULL,
- *user_table =NULL,
- *login_field =NULL,
-+ *concat_str =NULL,
-+ *separators_set =NULL,
- *chpass_clause =NULL; /* siefca@pld.org.pl */
-
- if (!mysql)
-@@ -834,14 +956,23 @@
- }
- else
- {
-+ concat_str = read_env ("USER_DOMAIN_CONCAT");
-+ separators_set = read_env ("USER_DOMAIN_SEPARATORS");
-+
-+ if (!concat_str || *concat_str == '\0')
-+ concat_str = DEF_CONCAT_STRING;
-+ if (!separators_set || *separators_set == '\0')
-+ separators_set = DEF_SEPARATORS_SET;
-+
- sql_buf=parse_chpass_clause(chpass_clause,
- user,
- defdomain,
-+ concat_str,
-+ separators_set,
- pass,
- newpass_crypt);
- }
-
--
- if (!sql_buf)
- {
- free(newpass_crypt);
-diff -ur courier-imap-1.4.2.orig/authlib/authmysqlrc courier-imap-1.4.2/authlib/authmysqlrc
---- courier-imap-1.4.2.orig/authlib/authmysqlrc Tue Jan 8 06:20:46 2002
-+++ courier-imap-1.4.2/authlib/authmysqlrc Thu Feb 14 00:19:43 2002
-@@ -141,65 +141,91 @@
- #
- # MYSQL_WHERE_CLAUSE server='mailhost.example.com'
-
--##NAME: MYSQL_SELECT_CLAUSE:0
-+##NAME: USER_DOMAIN_CONCAT:0
- #
--# (EXPERIMENTAL)
--# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database,
--# which is structuraly different from proposed. The fixed string will
--# be used to do a SELECT operation on database, which should return fields
--# in order specified bellow:
--#
--# username, cryptpw, uid, gid, clearpw, home, maildir, quota, fullname
--#
--# Enabling this option causes ignorance of any other field-related
--# options, excluding default domain.
--#
--# There are two variables, which you can use. Substitution will be made
--# for them, so you can put entered username (local part) and domain name
--# in the right place of your query. These variables are:
--# $(local_part) and $(domain)
-+# This is optional. Here you can set the string used to concatenate
-+# usename with domain part while expanding the $(username) substitution
-+# variable. If it's not set the '@' character is used.
- #
--# If a $(domain) is empty (not given by the remote user) the default domain
--# name is used in its place.
-+# USER_DOMAIN_CONCAT @
-+
-+##NAME: USER_DOMAIN_SEPARATORS:0
- #
--# This example is a little bit modified adaptation of vmail-sql
--# database scheme:
-+# This is optional. Using this option you can set the set of characters
-+# which are treated as separators when splitting entered username into the
-+# local part and the domain name. If it's not set the default set @% is used,
-+# do the user can log on using user@domain or user%domain.
- #
--# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
--# CONCAT('{MD5}', popbox.password_hash), \
--# domain.uid, \
--# domain.gid, \
--# popbox.clearpw, \
--# CONCAT(domain.path, '/', popbox.mbox_name), \
--# '', \
--# domain.quota, \
--# '', \
--# FROM popbox, domain \
--# WHERE popbox.local_part = '$(local_part)' \
--# AND popbox.domain_name = '$(domain)' \
--# AND popbox.domain_name = domain.domain_name
-+# USER_DOMAIN_SEPARATORS @%+
-+
-+##NAME: MYSQL_SELECT_CLAUSE:0
-+#
-+# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database,
-+# which is structuraly different from proposed. You can type here your MySQL
-+# query, which will be used to fetch user's credentials, and which should
-+# return fields in order specified bellow:
-+#
-+# username, cryptpw, clearpw, uid, gid, home, maildir, quota, fullname
-+#
-+# Enabling this option causes ignorance of any other field-related options.
-+#
-+# There also are variables, which you can use. Substitution will be made
-+# for them, so you can pass currently entered username and a domain name
-+# up to the right place within your query. These variables are:
-+# $(local_part) , $(domain) , $(username)
- #
-+# If a $(domain) is empty (not given by the remote user) the default domain
-+# name is used in its place. $(username) is a local part concatenated with
-+# domain name using symbol defined in USER_DOMAIN_CONCAT or '@' if this option
-+# is not set.
-+#
-+# MYSQL_SELECT_CLAUSE SELECT \
-+# users.username, users.cryptpw, users.clearpw, \
-+# domains.uid, domains.gid, \
-+# CONCAT_WS('/',domains.path_prefix,users.mailbox_path), \
-+# '', domains.quota, '' \
-+# FROM users, domains \
-+# WHERE domains.domain_name='$(domain)' \
-+# AND users.username='$(local_part)' \
-+# AND domains.domain_name=users.domain_name
-+
- ##NAME: MYSQL_CHPASS_CLAUSE:0
- #
--# (EXPERIMENTAL)
- # This is optional, MYSQL_CHPASS_CLAUSE can be set when you have a database,
--# which is structuraly different from proposed. The fixed string will
--# be used to do an UPDATE operation on database. In other words, it is
--# used, when changing password.
-+# which is structuraly different from proposed. You can use it to set up
-+# a MySQL query used to change user's password.
- #
- # There are four variables, which you can use. Substitution will be made
--# for them, so you can put entered username (local part) and domain name
-+# for them, so you can put the currently entered username and the domain name
- # in the right place of your query. There variables are:
--# $(local_part) , $(domain) , $(newpass) , $(newpass_crypt)
-+# $(local_part) , $(domain) , $(username) , $(newpass) , $(newpass_crypt)
- #
- # If a $(domain) is empty (not given by the remote user) the default domain
--# name is used in its place.
--# $(newpass) contains plain password
--# $(newpass_crypt) contains its crypted form
--#
--# MYSQL_CHPASS_CLAUSE UPDATE popbox \
--# SET clearpw='$(newpass)', \
--# password_hash='$(newpass_crypt)' \
--# WHERE local_part='$(local_part)' \
--# AND domain_name='$(domain)'
-+# name is used in its place. $(newpass) contains plain password and
-+# $(newpass_crypt) contains its crypted form.
-+#
-+# MYSQL_CHPASS_CLAUSE UPDATE users \
-+# SET clearpw='$(newpass)', \
-+# cryptpw='$(newpass_crypt)' \
-+# WHERE username='$(local_part)' \
-+# AND domain_name='$(domain)'
-+
-+##NAME: MYSQL_ONSUCCESS_CLAUSE:0
-+#
-+# This is optional, MYSQL_ONSUCCESS_CLAUSE is a trigger - the query is performed
-+# each time user has successfuly logged in. [experimental]
-+#
-+# MYSQL_ONSUCCESS_CLAUSE UPDATE users \
-+# SET last_ok=CURRENT_TIMESTAMP \
-+# WHERE username='$(local_part)' \
-+# AND domain_name='$(domain)'
-+
-+##NAME: MYSQL_ONFAIL_CLAUSE:0
-+#
-+# This is optional, MYSQL_ONFAIL_CLAUSE is a trigger - the query is performed
-+# each time user has successfuly logged in. [experimental]
- #
-+# MYSQL_ONFAIL_CLAUSE UPDATE users \
-+# SET last_fail=CURRENT_TIMESTAMP \
-+# WHERE username='$(local_part)' \
-+# AND domain_name='$(domain)'