diff -ur courier-imap-1.5.3-orig/authlib/README.authmysql.myownquery courier-imap-1.5.3/authlib/README.authmysql.myownquery
--- courier-imap-1.5.3-orig/authlib/README.authmysql.myownquery Tue Jan 8 06:01:22 2002
-+++ courier-imap-1.5.3/authlib/README.authmysql.myownquery Sat Sep 28 18:49:00 2002
++++ courier-imap-1.5.3/authlib/README.authmysql.myownquery Mon Oct 14 01:05:11 2002
@@ -2,13 +2,18 @@
- Developer Notes for courier-imap-myownquery.patch
+
+ Developer Notes and Usage Instructions
+
+ of
+
+ courier-imap-authmysql-myownquery
++ by
++
++ Pawel Wilk <siefca@kernel.pl>
-+ document version: 1.32
-+ patch for version: 1.5.3
-+ author: Pawel Wilk <siefca@kernel.pl>
-
- document version: 1.03
- author: Pawel Wilk
-@@ -21,71 +26,749 @@
+@@ -19,75 +24,843 @@
+
+
++ .. table of contents..
++PREAMBLE
+
+PART I - Usage Instructions
+ 1 What's that?
+ 3.2 queries
+ 3.3 substitutions
+ 3.4 triggers
++ 3.5 empty default domain name
++ 3.6 whitespaces in queries
+
+ 4 Examples of usage
+ 4.1 corporate mail system
+ 4.10 parse_select_clause
+ 4.11 parse_chpass_clause
+ 4.12 auth_mysql_on_trigger
++ 4.13 auth_mysql_on_pass
++ 4.14 auth_mysql_checkpassword
+ 5 Ideas and TODO
-+ 6 Thanks
-
-0 What's that?
++ 6 Thanks
-1 Modifications overview
- 4.10 parse_chpass_clause
-
-5 Ideas and TODO
-+//////////////////////////////// PART I - Usage ///////////////////////////////
+
+-6 Thanks
+
+
++//////////////////////////////// PREAMBLE /////////////////////////////////////
+
-+ *-----------------------
-+ 1 What's that?
-+ *-----------------------
++This is README document for "myownquery" patch for Courier's Authdaemon.
++This document version is 1.36
++
++* The patch, which this document describes is developed for Courier-IMAP
++ version 1.5.3 and the official patch revision is 2.
++
++* You can download the patch from the FTP server using URI:
+
-+Courier-imap-myownquery's features allow the 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 one to write a
-+SELECT and UPDATE clause in the configuration file (authmysqlrc) using
-+the new configuration options. It may be useful in mail environments where
-+there is a need to have a different database structure and/or tables
-+scheme than expected by authmysql module.
++ftp://ftp.pld.org.pl/people/siefca/patches/courier/courier-imap-1.5.3-myownquery.patch
--6 Thanks
-+It also implements a small parsing engine for substitution of variables which
-+may appear in the SQL clauses, such as a username or a domain.
++ it should also be accessible on mirroring servers, which list can be
++ obtained under: http://www.pld.org.pl/
++
++* To know more about getting Courier see http://www.courier-mta.org/
++
++* This patch, including the documentation, is released under GNU GPL
++ license terms. You should look at the COPYING file present in
++ Courier sources.
++
++.
++.
++.
++.
++.
++.
++
++//////////////////////////////// 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's features allow the 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
++one to write a SELECT and UPDATE clause in the configuration file
++(authmysqlrc) using the new configuration options. It may be useful in
++mail environments where there is a need to have a different database
++structure and/or tables scheme than expected by authmysql module.
++
++It also implements a small parsing engine for substitution of
++variables which may appear in the SQL clauses, such as a username or a
++domain.
+-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.
+
+-This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
-+
+ *-----------------------
+ 2 When will I need it?
- *-----------------------
-- 0 What's that?
++ *-----------------------
+
-+ o When you already have some MySQL database filled up with the data
++ 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
-+ work with a standard authmysql table. Typical situation is when all the
-+ data required to authenticate a user is arranged in more than one table.
++ work with a 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
++ 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
++ 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?
+ *-----------------------
+
+
+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:
++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)
+
+ The server name, userid, and password used to log in.
+
-+MYSQL_DATABASE (required)
++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)
++DEFAULT_DOMAIN (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.
++ If DEFAULT_DOMAIN is defined, and someone tries to log
++ in as 'user', we will look up 'user@DEFAULT_DOMAIN'
++ instead.
+
-+USER_DOMAIN_SEPARATORS (optional)
++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.
++ 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
+
+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.
++ These are the major options you should use. See 3.2
++ section for more info.
+
-+MYSQL_ONSUCCESS_CLAUSE (optional)
-+MYSQL_ONFAIL_CLAUSE (optional)
++ON_PASS_OK_CLAUSE (optional)
++ON_PASS_FAIL_CLAUSE (optional)
++ON_PASS_CHANGE_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).
++ These are used to do a MySQL query whether user has
++ passed the authentication verification
++ (ON_PASS_OK_CLAUSE) or there was the authentication
++ failure (ON_PASS_FAIL_CLAUSE), or whether user has
++ changed his password (ON_PASS_CHANGE_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.
+
+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.
++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:
++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
++* username - which is the currently logged user's username (or the
++ username with domain if you want it)
+
-+* clearpw - which is the user's plaintext password
++ 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
++* 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
++* gid - as above, but refers to GID
+
-+* home - which contains full path to the user's home directory
++* 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
++ maildir - which contains the directory name inside the user's home;
++ 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
++quota - which describes a quota size for the mailbox
+
-+fullname - which may contain the user's fullname
++fullname - which may contain the user's fullname
+
+(The fields marked by the asterix sign are required and cannot have an
-+ empty results)
++ empty results. In case of passwords, at least one of the shown fields
++ should contain some result.)
+
+So, the typical query clause may start with:
+
+
+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).
++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:).
++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.
++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.
++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
++context: MYSQL_SELECT_CLAUSE, ON_PASS_FAIL_CLAUSE, ON_PASS_OK_CLAUSE,
++ ON_PASS_CHANGE_CLAUSE
+
-+$(local_part) will be replaced by currently verified user's username
++$(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
++$(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
++$(username) will be replaced by currently verified user's username
++ concatenated with the given domain name using
++ @ symbol -- if the domiain name cannot be
++ obtained (even looking up DEFAULT_DOMAIN) the
++ separation sign will not appear and only the
++ given username will be presented
+
+context: MYSQL_CHPASS_CLAUSE
+
+ 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
++ concatenated with the given domain name using
++ @ symbol -- 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)
++ 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:
++Triggers are MySQL queries, which are performed depending on
++authentication state. Currently, there are three triggers which you
++may use. First is called ON_PASS_OK_CLAUSE and it is performed when
++the authentication succeedes. The second is called
++ON_PASS_FAIL_CLAUSE and has the reverse meaning. The third, which name
++is ON_PASS_CHANGE_CLAUSE is performed whenever user has changed his
++password.
++
++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 \
++ON_PASS_OK_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 \
++ON_PASS_FAIL_CLAUSE UPDATE users SET last_bad_login=CURRENT_TIMESTAMP \
+ WHERE username='$(username)';
-
--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.
++
++and/or, if you want to know last password changes you can use:
++
++ON_PASS_CHANGE_CLAUSE UPDATE users SET pw_change=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.
-
--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.
-
--This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
-
-
-
-
++MYSQL_SELECT_CLAUSE. Also note, that if the entered username
++doesn't match any real user ON_PASS_FAIL_CLAUSE will be simply
++discarded. To watch brute force attacs against known usernames
++you have to use log files. ;]
++
++3.5 empty default domain name
++
++Sometimes happens, that you want to allow user to log in without
++having a domain name entered and you expect it will be treated as an
++empty string, neither an error, nor default domain. In that case you
++should leave DEFAULT_DOMAIN option unset in authmysqlrc file and your
++database should have empty (not NULL) string fields for users without
++the domain name specified.
++
++3.6 whitespaces in queries
++
++In a few examples, here and in authmysqlrc file, I used to put many
++whitespaces and tabs to make the examples more clear for reader.
++However, it is recommended to not torture authdaemon's parser in
++that way and to remove unnecessary characters. ;]
++
++For example, the clause:
++
++MYSQL_CHPASS_CLAUSE UPDATE \
++ users \
++ SET clearpw='$(newpass)', \
++ cryptpw='$(newpass_crypt)' \
++ WHERE username='$(local_part)' \
++ AND domain_name='$(domain)'
++
++can be safetly rewritten as:
++
++MYSQL_CHPASS_CLAUSE UPDATE users \
++SET clearpw='$(newpass)', cryptpw='$(newpass_crypt)' \
++WHERE username='$(local_part)' AND domain_name='$(domain)'
++
++
++
++
++
++
+ *-----------------------
+ 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:
++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 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
-+ammount of served virtual domains. The database scheme was derived from tpop3d
-+documentation and modified a bit.
++ammount 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.
++credentials from the data describing domains.
+
-+Let's create some tables for our example, filled up with an example data:
++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
++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 |
+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
++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 |
+ | 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).
++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 database vmail;
+
-+# Create an example MySQL user, which can read, write and delete data from
-+# vmail database. Username: vuser Password: secret_password
++# 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
+
+--------------------- 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.
++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
+
+ 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.
++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)' \
++MYSQL_CHPASS_CLAUSE UPDATE \
++ users \
++ SET clearpw='$(newpass)', \
++ cryptpw='$(newpass_crypt)' \
++ WHERE username='$(local_part)' \
+ AND domain_name='$(domain)'
+
+And finally...
+
+4.2 virtual mail domains provider
+
-+Let's consider more complicated database scheme, where there 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 proper data separation I mean
-+avoiding unwanted redundancy in the database.
++Let's consider more complicated database scheme, where there 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 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.
++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
+
+ | 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. :)
++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
+
+
+CREATE database vmail;
+
-+# Create an example MySQL user, which can read, write and delete data from
-+# vmail database. Username: vuser Password: secret_password
++# 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
+
+--------------------- 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.
++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
+.
+
+/////////////////////////// PART II - Developer Notes /////////////////////////
-
++
*-----------------------
1 Modifications overview
*-----------------------
-Changes in the current source code are related to:
+Changes in the source code are related to:
- - sections where the queries are constructed
+-- sections where the queries are constructed
++- sections where the queries are constructed [authmysqllib.c]
(including memory allocation for the buffers)
-@@ -102,6 +785,10 @@
+
+ when MYSQL_SELECT_CLAUSE or MYSQL_CHPASS_CLAUSE is
+@@ -95,17 +868,29 @@
+ passing over current memory allocation and query construction
+ subroutines
+
+-- section where the configuration file is read
++- section where the configuration file is read [authmysqllib.c]
+
+ i've had to modify read_env() function to allow line breaks
+- - now each sequence of the backslash as a first character and
++ -- now each sequence of the backslash as a first character and
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
++ i've also added USER_DOMAIN_SEPARATORS configuration option --
++ it is used by get_localpart(), get_domain() and get_username()
++ functions, which are described below
+
- - sections where the query is constructed
++- sections where the query is constructed [authmysqllib.c]
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).
+- are set or not - if own query is used
++ are set or not -- if own query is used
++
++- sections where the user is authenticated against the authinfo [authmysql.c]
++
++ i've detached a part of code responsible for authentication
++ against crypted and plain password -- now it is in stub
++ function called auth_mysql_checkpassword() -- due to obtain
++ more clean code in auth_mysql_login() and
++ auth_mysql_changepw() around trigger calling functions
--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.
+
+
+@@ -123,14 +908,20 @@
+
+ These definitions allows to change substitution marks in an easy way.
+ SV_BEGIN_MARK refers to sequence of characters treated as a prefix of
+-each substitution variable and SV_END_MARK refers to string which is
+-a closing suffix. If the expected substitution variable is called
++each substitution variable and SV_END_MARK refers to string which is a
++closing suffix. If the expected substitution variable is called
+ 'local_part' (without apostrophes) then '$(local_part)' is a valid
+-string representation for SV_BEGIN_MARK set to "$(" and SV_END_MARK to ")".
+-MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
+-identifier (name).
++string representation for SV_BEGIN_MARK set to "$(" and SV_END_MARK to
++")". MAX_SUBSTITUTION_LEN defines maximal length of a substitution
++variable's identifier (name).
+
-+#define DEF_CONCAT_STRING "@"
-+#define DEF_SEPARATORS_SET "@%"
++The last two definitions (SV_BEGIN_LEN and SV_END_LEN) are just for
++code simplification.
+
-+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.
++#define DEF_SEPARATORS_SET "@%"
+
+-The last two definitions are just for code simplification.
++The DEF_SEPARATORS_SET directive defines the set of characters, which
++are treated as separators when splitting local part from the domain.
+
+
+@@ -152,10 +943,10 @@
+ size_t value_length;
+ } ;
+-This structure holds information needed by parsing routines.
+-Using var_data array you may specify a set of string substitutions
+-which should be done while parsing a query. Last element in array
+-should have all fields set to zero (null).
++This structure holds information needed by parsing routines. Using
++var_data array you may specify a set of string substitutions which
++should be done while parsing a query. Last element in array should
++have all fields set to zero (null).
+
+ name field - should contain substituted variable name
+ value - should contain string which replaces it
+@@ -164,9 +955,9 @@
+
+
+ explanation: size is used to increase speed of calculation proccess
+- value_length is used to cache length of a value during the
+- parsing subroutines - it helps when substitution variable
+- occures more than once within the query
++ value_length is used to cache length of a value during
++ the parsing subroutines - it helps when substitution
++ variable occures more than once within the query
+
+ Example:
+
+@@ -177,18 +968,19 @@
+ };
-@@ -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
+-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.
++replaced by 'replacement' text, and replacement for $(anotha) will be
++set later in the code, before passing on the array pointer to the
++general parsing function.
3.2 typedef size_t (*parsefunc)
-@@ -230,6 +926,10 @@
+
+ typedef int (*parsefunc)(const char *, size_t, void *);
+
+-This type definition refers to the function pointer, which is used
+-to pass plugin functions into the core parsing subroutine. This definition
+-is included to simplify the declaration of the parse_core() function.
++This type definition refers to the function pointer, which is used to
++pass plugin functions into the core parsing subroutine. This
++definition is included to simplify the declaration of the parse_core()
++function.
+
+
+
+@@ -230,6 +1022,10 @@
structure of var_data type, which contains variable definition
of a given name. It returns NULL on error or failure.
4.2 parse_core
-@@ -285,6 +985,11 @@
+@@ -285,6 +1081,11 @@
This function returns -1 if an error has occured and 0 if
everything went good.
4.3 ParsePlugin_counter
-@@ -314,6 +1019,11 @@
+@@ -314,6 +1115,11 @@
This function returns the variable size or -1 if an error
has occured, 0 if everything went good.
4.4 ParsePlugin_builder
NAME
-@@ -333,7 +1043,7 @@
+@@ -333,7 +1139,7 @@
type pointer and refers to the (char *) pointer variable.
After each call it shifts the value of pointer variable (char *)
incrementing it by len bytes. Be careful when using this function
additional pointer type variable when passing it as the third
argument.
-@@ -342,6 +1052,10 @@
+@@ -342,6 +1148,10 @@
This function returns the variable size or -1 if an error
has occured, 0 if everything went good.
4.5 parse_string
NAME
-@@ -353,7 +1067,7 @@
+@@ -353,7 +1163,7 @@
DESCRIPTION
replacement instructions set in var_data array, which is passed with
its pointer vdt. It produces changed string located in newly allocated
memory area.
-@@ -377,6 +1091,10 @@
+@@ -377,6 +1187,10 @@
Function returns pointer to the result buffer or NULL
if an error has occured.
WARNINGS
This function allocates some amount of memory using standard
-@@ -405,6 +1123,10 @@
+@@ -405,6 +1219,10 @@
It returns a pointer to the static buffer which contains
validated password string or NULL if an error has occured.
4.7 get_localpart
-@@ -414,20 +1136,28 @@
+@@ -414,20 +1232,28 @@
SYNOPSIS
4.8 get_domain
-@@ -438,24 +1168,68 @@
+@@ -438,24 +1264,67 @@
SYNOPSIS
static const char *get_domain (const char *username,
+FILES
+
+ authlib/authmysqllib.c
-+
-4.9 parse_select_clause
++
+4.9 get_username
+
+NAME
+SYNOPSIS
+
+ static const char *get_username (const char *username,
-+ const char *domainname,
-+ const char *concat_str);
++ const char *domainname);
+
+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.
++ using the @ symbol. If the domain is empty or NULL the result
++ comes without binding symbol.
+
+RETURN VALUE
+
NAME
-@@ -465,7 +1239,9 @@
+@@ -465,23 +1334,34 @@
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 +1249,21 @@
+ This function is a simple wrapper to the parse_string()
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 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.
++ and defdomain strings are used to create corresponding
++ substitution strings if present in the query: $(local_part),
++ $(domain), and $(username). Note, that username parameter
++ may contain 'user@domain' form here, so the call to
++ get_localpart() and get_domain() function will split it
++ into two parts, then calling get_username() function will join
++ it again using the @ symbol. This trick is wanted as long as
++ we'd like to have possibility to split the local part from the
++ domain by using dynamic symbols set. The separators_set is
++ passed to get_localpart() and get_domain() invocations.
-
RETURN VALUE
NAME
-@@ -492,6 +1274,8 @@
+@@ -492,6 +1372,7 @@
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 +1286,56 @@
+@@ -502,12 +1383,115 @@
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().
++ $(newpass_crypt). The separators_set is passed to
++ get_localpart() and get_domain() functions as described in the
++ entry for parse_select_clause().
RETURN VALUE
+
+DESCRIPTION
+
-+ This function is responsible for calling out the MySQL queries
++ This function is responsible for calling out the MySQL queries
+ depending on 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).
++ 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.
++ This function reads DEFAULT_DOMAIN 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.
++ This function returns 0 on success and -1 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.
++
++FILES
++
++ authlib/authmysqllib.c
++
++
++4.13 auth_mysql_on_pass
++
++NAME
++
++ auth_mysql_on_pass
++
++SYNOPSIS
++
++ static int auth_mysql_on_pass(const char *clause,
++ struct authmysqluserinfo *authinfo);
++
++DESCRIPTION
++
++ This function is responsible for invoking trigger MySQL
++ clauses whenever user is authenticated or not.
++ This is a stub function, which calls auth_mysql_on_trigger().
++ Firstly, it does a simple checks in authinfo structure --
++ it looks for a valid username field. If username is not set
++ or it's empty the fuction does nothing. This behavior follows
++ the need, that if there wasn't any valid username then we
++ shouldn't touch the database.
++
++RETURN VALUE
++
++ It returns 0 in case everything went fine, -1 if there was some
++ error.
+
+FILES
+
-+ authlib/authmysql.h
+ authlib/authmysql.c
++
++
++4.14 auth_mysql_checkpassword
++
++NAME
++ auth_mysql_checkpassword
++
++SYNOPSIS
++
++ static int auth_mysql_checkpassword(struct authmysqluserinfo *authinfo, const char *pass);
++
++DESCRIPTION
++
++ This function is a wrapper, which checks user's entered
++ password against one found in a database. Function tries to
++ authenticate user against his crypted password and if it's
++ impossible it tries the plain form -- by impossible we mean
++ the authinfo->cryptpw set to NULL.
++
++RETURN VALUE
++
++ Function returns 0 if the password was correct, -1 if user
++ applied bad password of the username wasn't found.
++
++FILES
++
++ authlib/authmysql.c
++
-@@ -520,11 +1348,9 @@
- strings after split (problem?)
+@@ -516,15 +1500,10 @@
+ 5 Ideas and TODO
+ *------------------------
+
+-- solve problem with fixed buffer length of local part and the domain part
+- 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
-
-
- - 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 +1360,20 @@
+@@ -534,10 +1513,20 @@
6 Thanks
*------------------------
-I would also thank Philip Hazel, Chris Lightfoot and Mike Bremford which
-by their software capabilities inspired me to write it.
+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
+
+Jacek Surazski
+ for reviewing this document just before it was published
- ---------------------------------------------------------------------------
-
++---------------------------------------------------------------------------
++ Any comments and suggestions are welcome.
diff -ur courier-imap-1.5.3-orig/authlib/authmysql.c courier-imap-1.5.3/authlib/authmysql.c
--- courier-imap-1.5.3-orig/authlib/authmysql.c Sun Jun 24 01:42:05 2001
-+++ courier-imap-1.5.3/authlib/authmysql.c Sat Sep 28 18:46:50 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;
-+
++++ courier-imap-1.5.3/authlib/authmysql.c Sun Oct 13 23:12:06 2002
+@@ -19,7 +19,47 @@
+ #include "authmysql.h"
+ #include "authstaticlist.h"
+
+-static const char rcsid[]="$Id$";
++static const char rcsid[]="$Id$";
++
++/* siefca@pld.org.pl */
++static int auth_mysql_on_pass(const char *clause, struct authmysqluserinfo *authinfo)
++{
++ if (authinfo->username && *(authinfo->username)!='\0') /* do it if user was found */
++ {
++ if (auth_mysql_on_trigger(clause, authinfo->username))
++ {
++ return (-1); /* MySQL error or something critical.. */
++ }
++ }
++
++ return (0);
++}
++
++/* siefca@pld.org.pl */
++static int auth_mysql_checkpassword(struct authmysqluserinfo *authinfo,
++ const char *pass)
++{
++ if (authinfo->cryptpw)
++ {
++ if (authcheckpassword(pass,authinfo->cryptpw))
++ {
++ return (-1); /* User/Password not found. */
++ }
++ }
++ else if (authinfo->clearpw)
++ {
++ if (strcmp(pass, authinfo->clearpw))
++ {
++ return (-1);
++ }
++ }
++ else
++ {
++ return (-1);
++ }
++
++ return (0);
++}
+
+ static char *auth_mysql_login(const char *service, char *authdata,
+ int issession,
+@@ -46,26 +86,23 @@
return (0);
}
-@@ -50,7 +54,11 @@
+- if (authinfo->cryptpw)
++ /* siefca@pld.org.pl */
++ if (auth_mysql_checkpassword(authinfo,pass))
{
- 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))
- {
+- if (authcheckpassword(pass,authinfo->cryptpw))
+- {
++ if (auth_mysql_on_pass("ON_PASS_FAIL_CLAUSE", authinfo))
++ errno=EACCES;
++ else
+ errno=EPERM;
+- return (0); /* User/Password not found. */
+- }
+- }
+- else if (authinfo->clearpw)
+- {
+- if (strcmp(pass, authinfo->clearpw))
+- {
- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0);
- }
+- return (0);
+- }
++
++ return(0);
}
else
{
- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
-+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (0); /* Username not found */
+- return (0); /* Username not found */
++ if (auth_mysql_on_pass("ON_PASS_OK_CLAUSE", authinfo))
++ {
++ errno=EACCES;
++ return(0);
++ }
}
-@@ -132,6 +148,12 @@
- (*callback_func)(&aa, callback_arg);
+ if (callback_func == 0)
+@@ -149,26 +186,23 @@
+ return (-1);
}
-+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
-+ {
-+ errno=EACCES;
-+ return (0);
-+ }
-+
- return (strdup(authinfo->username));
- }
-
-@@ -153,7 +175,11 @@
+- if (authinfo->cryptpw)
++ /* siefca@pld.org.pl */
++ if (auth_mysql_checkpassword(authinfo, pass))
{
- if (authcheckpassword(pass,authinfo->cryptpw))
- {
+- 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); /* User/Password not found. */
+- }
+- }
+- else if (authinfo->clearpw)
+- {
+- if (strcmp(pass, authinfo->clearpw))
+- {
++ if (auth_mysql_on_pass("ON_PASS_FAIL_CLAUSE", authinfo))
++ errno=EACCES;
++ else
+ errno=EPERM;
+- return (-1);
+- }
+
- return (-1);
- }
++ return(-1);
}
else
{
- errno=EPERM;
-+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
+- return (-1);
++ if (auth_mysql_on_pass("ON_PASS_OK_CLAUSE", authinfo))
++ {
+ errno=EACCES;
-+ else
-+ errno=EPERM;
-+
- return (-1);
++ return(-1);
++ }
}
-@@ -176,6 +210,13 @@
+ if (auth_mysql_setpass(user, newpass))
+@@ -176,6 +210,14 @@
errno=EPERM;
return (-1);
}
+
-+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
++ /* siefca@pld.org.pl */
++ if (auth_mysql_on_pass("ON_PASS_CHANGE_CLAUSE", authinfo))
+ {
-+ errno=EACCES;
-+ return (-1);
++ errno=EACCES;
++ return (-1);
+ }
-+
++
return (0);
}
+@@ -314,7 +356,7 @@
+ #endif
+
+ char *auth_mysql(const char *service, const char *authtype, char *authdata,
+- int issession,
++ int issession,
+ void (*callback_func)(struct authinfo *, void *), void *callback_arg)
+ {
+ if (strcmp(authtype, AUTHTYPE_LOGIN) == 0)
diff -ur courier-imap-1.5.3-orig/authlib/authmysql.h courier-imap-1.5.3/authlib/authmysql.h
--- courier-imap-1.5.3-orig/authlib/authmysql.h Mon Aug 6 05:12:39 2001
-+++ courier-imap-1.5.3/authlib/authmysql.h Sat Sep 28 18:46:50 2002
++++ courier-imap-1.5.3/authlib/authmysql.h Sat Sep 28 00:01:07 2002
@@ -21,6 +21,7 @@
} ;
extern int auth_mysql_setpass(const char *, const char *);
diff -ur courier-imap-1.5.3-orig/authlib/authmysqllib.c courier-imap-1.5.3/authlib/authmysqllib.c
--- courier-imap-1.5.3-orig/authlib/authmysqllib.c Wed May 29 19:24:03 2002
-+++ courier-imap-1.5.3/authlib/authmysqllib.c Sat Sep 28 18:48:11 2002
-@@ -23,6 +23,9 @@
++++ courier-imap-1.5.3/authlib/authmysqllib.c Sun Oct 13 22:58:09 2002
+@@ -23,6 +23,8 @@
#define SV_END_MARK ")"
#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$";
-@@ -268,7 +271,7 @@
+@@ -268,7 +270,7 @@
SV_BEGIN_MARK
"%.*s"
SV_END_MARK
return NULL;
}
-@@ -426,21 +429,43 @@
+@@ -364,14 +366,14 @@
+ t_size = t_end-t_begin+1;/* text field length */
+
+ /* work on text */
+- if ( (outfn (t_begin, t_size, result)) == -1 )
++ if ( (outfn (t_begin, t_size, result)))
+ return -1;
+
+ /* work on variable */
+ v_ptr = get_variable (v_begin, v_size, vdt);
+ if (!v_ptr) return -1;
+
+- if ( (outfn (v_ptr->value, v_ptr->value_length, result)) == -1 )
++ if ( (outfn (v_ptr->value, v_ptr->value_length, result)))
+ return -1;
+
+ q = e + 1;
+@@ -379,7 +381,7 @@
+
+ /* work on last part of text if any */
+ if (*q != '\0')
+- if ( (outfn (q, strlen(q), result)) == -1 )
++ if ( (outfn (q, strlen(q), result)))
+ return -1;
+
+ return 0;
+@@ -426,21 +428,45 @@
return NULL;
}
*pass_buf = '\0';
/* 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 const char *get_username (const char *username, const char *domainname)
+{
++size_t u_len;
++char *p;
+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);
-+
++ if (!username || *username == '\0') return NULL;
++ u_len=strlen(username);
++ if (( u_len + (domainname ? strlen(domainname) : 0)
++ ) > 397) return NULL;
++
++ strcpy (username_buf, username);
++ if (domainname && *domainname != '\0')
++ {
++ p = username_buf + u_len;
++ *p='@'; p++;
++ strcpy(p, domainname);
++ }
++
+ return (username_buf);
+}
+
if (p)
{
if ((p-username) > 128)
-@@ -469,21 +494,27 @@
+@@ -469,21 +495,27 @@
}
/* siefca@pld.org.pl */
}
p++;
-@@ -531,20 +562,27 @@
+@@ -531,20 +563,25 @@
/* 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[]={
+ {"username", NULL, sizeof("username"), 0},
{NULL, NULL, 0, 0}};
- if (clause == NULL || *clause == '\0' ||
+- if (clause == NULL || *clause == '\0' ||
- !username || *username == '\0')
-+ !username || *username == '\0' ||
-+ !concat_str || *concat_str == '\0' ||
-+ !separators_set || *separators_set == '\0')
++ if (!clause || !username || !separators_set ||
++ *clause == '\0' || *username == '\0' ||
++ *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);
++ vd[2].value = get_username (vd[0].value, vd[1].value);
+
+ if (!vd[0].value || !vd[1].value || !vd[2].value)
return NULL;
return (parse_string (clause, vd));
-@@ -552,12 +590,16 @@
+@@ -552,12 +589,15 @@
/* 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)
{
{"newpass", NULL, sizeof("newpass"), 0},
{"newpass_crypt", NULL, sizeof("newpass_crypt"), 0},
{NULL, NULL, 0, 0}};
-@@ -565,19 +607,83 @@
+@@ -565,19 +605,81 @@
if (clause == NULL || *clause == '\0' ||
!username || *username == '\0' ||
!newpass || *newpass == '\0' ||
- 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[3].value = get_username (vd[0].value, vd[1].value);
+ vd[4].value = validate_password (newpass);
+ vd[5].value = validate_password (newpass_crypt);
+int auth_mysql_on_trigger (const char *clause_name, const char *username)
+{
+char *querybuf =NULL;
-+const char *concat_str =NULL,
-+ *separators_set =NULL,
++const char *separators_set =NULL,
+ *defdomain =NULL,
+ *on_clause =NULL;
+MYSQL_RES *result;
+
-+ if (!clause_name || *clause_name == '\0') return (0);
++ if (!clause_name || *clause_name == '\0')
++ return (-1);
++
+ on_clause = read_env (clause_name);
-+ if (!on_clause || *on_clause == '\0') return (1);
++ if (!on_clause || *on_clause == '\0')
++ return (0); /* ok! not in use */
+
+ 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 (!querybuf) return (-1);
+
+ if (mysql_query (mysql, querybuf))
+ {
+ if (do_connect())
+ {
+ free(querybuf);
-+ return (1);
++ return (-1);
+ }
+
+ if (mysql_query (mysql, querybuf))
+ /* Server went down, that's OK,
+ ** try again next time.
+ */
-+ return (1);
++ return (-1);
+ }
+ }
+ free(querybuf);
+ result = mysql_store_result(mysql);
+ if (result) mysql_free_result(result);
+
-+ return (1);
++ return (0);
+}
+
+
struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username)
{
const char *user_table =NULL;
-@@ -596,6 +702,8 @@
+@@ -596,6 +698,7 @@
*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[]=
-@@ -704,7 +812,19 @@
+@@ -704,7 +807,15 @@
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;
}
-@@ -788,6 +908,8 @@
+@@ -788,6 +899,7 @@
*where_clause =NULL,
*user_table =NULL,
*login_field =NULL,
-+ *concat_str =NULL,
+ *separators_set =NULL,
*chpass_clause =NULL; /* siefca@pld.org.pl */
if (!mysql)
-@@ -837,13 +959,22 @@
+@@ -837,13 +949,18 @@
}
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_ptr);
if (!sql_buf)
{
-Only in courier-imap-1.5.3/authlib: authmysqllib.c.orig
-Only in courier-imap-1.5.3/authlib: authmysqllib.c.rej
diff -ur courier-imap-1.5.3-orig/authlib/authmysqlrc courier-imap-1.5.3/authlib/authmysqlrc
--- courier-imap-1.5.3-orig/authlib/authmysqlrc Thu Apr 4 06:36:29 2002
-+++ courier-imap-1.5.3/authlib/authmysqlrc Sat Sep 28 18:46:50 2002
++++ courier-imap-1.5.3/authlib/authmysqlrc Mon Oct 14 00:02:59 2002
@@ -1,4 +1,4 @@
-##VERSION: $Id$
+##VERSION: $Id$
-# 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
-+##NAME: USER_DOMAIN_CONCAT:0
- #
--# Enabling this option causes ignorance of any other field-related
--# options, excluding default domain.
-+# This is optional. Here, you can write the string used to concatenate
-+# username with domain part while expanding the $(username) substitution
-+# variable. If it's not set the '@' character is used.
-+# See README.authmysql.myownquery for more information
- #
--# 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)
-+# USER_DOMAIN_CONCAT @
-+
+##NAME: USER_DOMAIN_SEPARATORS:0
#
--# If a $(domain) is empty (not given by the remote user) the default domain
--# name is used in its place.
+-# username, cryptpw, uid, gid, clearpw, home, maildir, quota, fullname
+# 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 defaults @% are used,
+# so the user can authenticate using user@domain or user%domain form.
+# See README.authmysql.myownquery for more information
#
--# This example is a little bit modified adaptation of vmail-sql
--# database scheme:
+-# Enabling this option causes ignorance of any other field-related
+-# options, excluding default domain.
+# USER_DOMAIN_SEPARATORS @%+
+
+##NAME: MYSQL_SELECT_CLAUSE:0
#
--# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
--# CONCAT('{MD5}', popbox.password_hash), \
--# popbox.clearpw, \
--# domain.uid, \
--# domain.gid, \
--# 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
+-# 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, 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
+# 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
+ # If a $(domain) is empty (not given by the remote user) the default domain
+-# name is used in its place.
+-#
+-# This example is a little bit modified adaptation of vmail-sql
+-# database scheme:
+-#
+-# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
+-# CONCAT('{MD5}', popbox.password_hash), \
+-# popbox.clearpw, \
+-# domain.uid, \
+-# domain.gid, \
+-# 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
+-#
+# 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.
-# 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.
+# See README.authmysql.myownquery for more information
+# WHERE username='$(local_part)' \
+# AND domain_name='$(domain)'
+
-+##NAME: MYSQL_ONSUCCESS_CLAUSE:0
-+# (EXPERIMENTAL)
++##NAME: ON_PASS_OK_CLAUSE:0
+#
-+# This is optional, MYSQL_ONSUCCESS_CLAUSE is a trigger - the query is performed
-+# each time user has successfuly logged in.
++# This is optional, ON_PASS_OK_CLAUSE is a trigger -- the query
++# is performed each time user has successfuly logged in.
+# See README.authmysql.myownquery for more information
+#
-+# MYSQL_ONSUCCESS_CLAUSE UPDATE users \
++# ON_PASS_OK_CLAUSE UPDATE users \
+# SET last_ok=CURRENT_TIMESTAMP \
+# WHERE username='$(local_part)' \
+# AND domain_name='$(domain)'
+
-+##NAME: MYSQL_ONFAIL_CLAUSE:0
-+# (EXPERIMENTAL)
- #
-+# This is optional, MYSQL_ONFAIL_CLAUSE is a trigger - the query is performed
-+# each time user has successfuly logged in.
++##NAME: ON_PASS_FAIL_CLAUSE:0
++#
++# This is optional, ON_PASS_FAIL_CLAUSE is a trigger -- the query
++# is performed each time user has NOT logged in, cause of bad password.
+# See README.authmysql.myownquery for more information
+#
-+# MYSQL_ONFAIL_CLAUSE UPDATE users \
++# ON_PASS_FAIL_CLAUSE UPDATE users \
+# SET last_fail=CURRENT_TIMESTAMP \
+# WHERE username='$(local_part)' \
+# AND domain_name='$(domain)'
++
++##NAME: ON_PASS_CHANGE_CLAUSE:0
++#
++# This is optional, ON_PASS_CHANGE_CLAUSE is a trigger -- the query
++# is performed each time user has successfuly changed his password.
++# See README.authmysql.myownquery for more information
++#
++# ON_PASS_CHANGE_CLAUSE UPDATE users \
++# SET pw_change=CURRENT_TIMESTAMP \
++# WHERE username='$(local_part)' \
++# AND domain_name='$(domain)'