]> git.pld-linux.org Git - packages/courier-imap.git/commitdiff
- courier-imap-myownquery-fix.patch added courier-imap-1_4_2-2
authorsiefca <siefca@pld-linux.org>
Wed, 13 Feb 2002 23:45:22 +0000 (23:45 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
 - added trigger clauses support
 - added configurable separation/concatenation symbols for local_part/domain
 - added '$(username)' substitution variable
 - added documentation for system administrators :>
 - allowed empty domain names in queries
 - fixed an example configuration file (authmysqlrc)

Changed files:
    courier-imap-myownquery-fix.patch -> 1.1
    courier-imap.spec -> 1.62

courier-imap-myownquery-fix.patch [new file with mode: 0644]
courier-imap.spec

diff --git a/courier-imap-myownquery-fix.patch b/courier-imap-myownquery-fix.patch
new file mode 100644 (file)
index 0000000..d4e60c0
--- /dev/null
@@ -0,0 +1,1613 @@
+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)'
index f4cf360f9d0ed05389412cb47ed3254c3a5f8e22..128f3f1259c8eb4052c8e02e0874b3dd445f01d1 100644 (file)
@@ -7,7 +7,7 @@ Summary:        Courier-IMAP server
 Summary(pl):   Serwer Courier-IMAP
 Name:          courier-imap
 Version:       1.4.2
-Release:       1
+Release:       2
 License:       GPL
 Group:         Networking/Daemons
 Group(cs):     Sí»ové/Démoni
@@ -33,6 +33,7 @@ Source5:      %{name}-pop3.pamd
 Source6:       %{name}.sysconfig
 Source7:       %{name}-pop3.sysconfig
 Source8:       %{name}-authdaemon.sysconfig
+Patch0:                ftp://ftp.pld.org.pl/people/siefca/patches/courier/%{name}-myownquery-fix.patch
 URL:           http://www.inter7.com/courierimap/
 %{!?_without_postgresql:BuildRequires: postgresql-devel}
 %{!?_without_mysql:BuildRequires:      mysql-devel}
@@ -261,6 +262,7 @@ IMAP.
 
 %prep
 %setup -q
+%patch0 -p1
 
 %build
 %configure2_13 \
This page took 0.092308 seconds and 4 git commands to generate.