1 diff -ur courier-imap-1.5.3.20020921.orig/authlib/README.authmysql.myownquery courier-imap-1.5.3.20020921/authlib/README.authmysql.myownquery
2 --- courier-imap-1.5.3.20020921.orig/authlib/README.authmysql.myownquery Tue Jan 8 06:01:22 2002
3 +++ courier-imap-1.5.3.20020921/authlib/README.authmysql.myownquery Sat Sep 28 01:19:55 2002
8 - Developer Notes for courier-imap-myownquery.patch
9 + Developer Notes and Usage Instructions
13 + courier-imap-authmysql-myownquery
17 + document version: 1.30
18 + patch for version: 1.5.3.20020921
19 + author: Pawel Wilk <siefca@kernel.pl>
21 - document version: 1.03
30 +PART I - Usage Instructions
34 + 2 When will I need it?
37 + 3.1 configuration variables
43 + 4.1 corporate mail system
44 + 4.1.1 database structure
45 + 4.1.2 authdaemon configuration
46 + 4.2 virtual mail domains provider
47 + 4.2.1 database structure
48 + 4.2.2 authdaemon configuration
50 +PART II - Developer Notes
52 + 1 Modifications overview
58 + 3.2 typedef size_t (*parsefunc)
63 + 4.3 ParsePlugin_counter
64 + 4.4 ParsePlugin_builder
66 + 4.6 validate_password
70 + 4.10 parse_select_clause
71 + 4.11 parse_chpass_clause
72 + 4.12 auth_mysql_on_trigger
80 -1 Modifications overview
86 - 3.2 typedef size_t (*parsefunc)
91 - 4.3 ParsePlugin_counter
92 - 4.4 ParsePlugin_builder
94 - 4.6 validate_password
97 - 4.9 parse_select_clause
98 - 4.10 parse_chpass_clause
101 +//////////////////////////////// PART I - Usage ///////////////////////////////
103 + *-----------------------
105 + *-----------------------
107 +Courier-imap-myownquery's features allow the administrator to set his own MySQL
108 +queries used by authdaemon to authenticate a user (including fetchig his
109 +credentials) and to change the user's password. It allows one to write a
110 +SELECT and UPDATE clause in the configuration file (authmysqlrc) using
111 +the new configuration options. It may be useful in mail environments where
112 +there is a need to have a different database structure and/or tables
113 +scheme than expected by authmysql module.
116 +It also implements a small parsing engine for substitution of variables which
117 +may appear in the SQL clauses, such as a username or a domain.
123 + *-----------------------
124 + 2 When will I need it?
125 *-----------------------
128 + o When you already have some MySQL database filled up with the data
129 + and there is no chance to change the whole structure to make it
130 + work with a standard authmysql table. Typical situation is when all the
131 + data required to authenticate a user is arranged in more than one table.
133 + o When you have some great idea how to make the database structure
134 + more efficient due to your needs and your requirements.
136 + o When doing something 'by-myself' is in your style and you just want
137 + to create your own database, just to feel the pleasure of doing
138 + something original. :)
144 *-----------------------
145 + 3 How does it work?
146 + *-----------------------
148 +There are three things which the feature concerns:
150 +- fetching clauses from the configuration file
151 +- doing substitution replacements inside of SQL clauses
152 +- passing prepared query on to the mysql interface funtions
154 +3.1 configuration options
156 +You can apply your own MySQL queries using a set of the configuration options.
157 +The options you'll need to make the authmysql your slave are:
159 +MYSQL_SERVER (required)
160 +MYSQL_USERNAME (required)
161 +MYSQL_PASSWORD (required)
163 + The server name, userid, and password used to log in.
165 +MYSQL_DATABASE (required)
167 + The name of the MySQL database we will open.
169 +DEFAULT_DOMAIN (optional)
171 + If DEFAULT_DOMAIN is defined, and someone tries to log in as
172 + 'user', we will look up 'user@DEFAULT_DOMAIN' instead.
174 +USER_DOMAIN_CONCAT (optional)
176 + The USER_DOMAIN_CONCAT defines a character(s) used to
177 + concatenate a local part and a domain while parsing
178 + the $(username) substitution variable (see section 3.3
179 + for more info). If it's not defined the @ sign is assumed.
181 +USER_DOMAIN_SEPARATORS (optional)
183 + This may contain the set of characters used by parsing
184 + routines to split local part of the virtual mailbox name
185 + from the part which describes the domain name. If it's not
186 + defined the set containing @% is assumed, so the user can
187 + enter either: user@domain or user%domain when he wants to be
190 +MYSQL_SELECT_CLAUSE (required)
191 +MYSQL_CHPASS_CLAUSE (required under some circumstances)
193 + These are the major options you should use. See 3.2 section
196 +MYSQL_ONSUCCESS_CLAUSE (optional)
197 +MYSQL_ONFAIL_CLAUSE (optional)
199 + These are used to do a MySQL query whether user has passed
200 + the authentication verification (MYSQL_ONSUCCESS_CLAUSE)
201 + or there was the authentication failure (MYSQL_ONFAIL_CLAUSE).
202 + Query results have no meaning. You can use the same
203 + substitution variables in your query as with
204 + MYSQL_SELECT_CLAUSE. See 3.4 section for more info.
206 +The options which have no effect, and may be safetly left blank are:
222 +The feature adds two configuration options (clauses), which are parsed first,
223 +and then applied as MySQL queries to MySQL interface routines. These options
224 +are: MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. After each option a number of
225 +spaces and/or tabs is allowed, and then MySQL query is expected. For better
226 +look, your queries can have line breaks. Each line break should be preceded by
227 +the backslash sign. Look into examples chapter (4) to see how it should look
228 +like. First clause is used to authenticate a user, and the second to change his
231 +You should note that a query identified by MYSQL_SELECT_CLAUSE should return
232 +fixed number (9) of fields and each field should match the variable expected
233 +by authentication routines. These fields are:
235 +* username - which is the currently logged user's username (or the
236 + username with domain if you want it)
238 +* cryptpw - which is the user's crypted password
240 +* clearpw - which is the user's plaintext password
242 +* uid - which is a numerical UID value used as a process's UID when
243 + accessing the mailbox directory
245 +* gid - as above, but refers to GID
247 +* home - which contains full path to the user's home directory
249 +maildir - which contains the directory name inside the user's home
250 + which is treated as INBOX folder when accessing mailbox
251 + - if it's empty then the 'Maildir' string is used
253 +quota - which describes a quota size for the mailbox
255 +fullname - which may contain the user's fullname
257 +(The fields marked by the asterix sign are required and cannot have an
260 +So, the typical query clause may start with:
262 +MYSQL_SELECT_CLAUSE SELECT \
268 + users.mailbox_path) \
274 +Note that in this short example we're assuming that we have two tables
275 +(users and domains) and INBOX path is always called 'Maildir' and
276 +we're not using the fullname field (the query will always return an empty
277 +string in its place).
279 +Also note that you may discard one of the password fields if you don't want
280 +to use an authentication mechanism, which needs it. For example, if you don't
281 +want to use MD5-CRAM you may put '' into the place of clearpw (because, for
282 +example you're in paranoid mode and you don't even want to keep plain passwords
287 +Substitutions are strings, which may appear in your query, and which have a
288 +special meaning. You can also call them substitution variables. If substitution
289 +variable is known for a clause context then it is parsed. If it isn't known the
290 +error is generated. In the default compilation of authmysql module any
291 +substitution variable is declared inside of two substrings - the first is a
292 +dollar sign concatenated with opening parenthesis, and the second is a closing
293 +parenthesis sign. First symbol identifies beginning of a substitution variable,
294 +and the second closes it. The string between the beginning and the closing
295 +symbol is called substitution variable's name.
297 +When, as I said before, the name is known to the parsing routine the
298 +substitution is made and the proper value appears in place of the substitution
299 +variable, while passing on the query for later processing.
301 +Allowed substitution variables:
303 +context: MYSQL_SELECT_CLAUSE, MYSQL_ONFAIL_CLAUSE, MYSQL_ONSUCCESS_CLAUSE
305 +$(local_part) will be replaced by currently verified user's username
306 + (without the domain part)
308 +$(domain) will be replaced by currently verified user's domain
309 + name (if present, or if not present but the
310 + DEFAULT_DOMAIN was used) or by the empty, zero-length
311 + string if the domain cannot be obtained
313 +$(username) will be replaced by currently verified user's username
314 + concatenated with the given domain name using symbol
315 + defined by USER_DOMAIN_CONCAT - if the domiain name
316 + cannot be obtained (even by looking up DEFAULT_DOMAIN)
317 + the separation sign will not appear and only the given
318 + username will be presented
320 +context: MYSQL_CHPASS_CLAUSE
322 +$(local_part) will be replaced by currently verified user's username
323 + (without the domain part)
325 +$(domain) will be replaced by currently verified user's domain
326 + name (if present, or if not present but the
327 + DEFAULT_DOMAIN was used) or by the empty, zero-length
328 + string if the domain cannot be obtained
330 +$(username) will be replaced by currently verified user's username
331 + concatenated with the given domain name using symbol
332 + defined by USER_DOMAIN_CONCAT - if the domiain name
333 + cannot be obtained (even by looking up DEFAULT_DOMAIN)
334 + the separation sign will not appear and only the given
335 + username will be presented
337 +$(newpass) will be replaced by currently authenticated user's
338 + new password to set up (plaintext password)
340 +$(newpass_crypt) will be replaced by currently authenticated user's
341 + new password to set up (MD5 form created from entered
346 +Triggers are MySQL queries, which are performed depending on authentication
347 +state. Currently, there are two triggers which you may use. First is called
348 +MYSQL_ONSUCCESS_CLAUSE and it is performed when the authentication succeedes.
349 +The second is called MYSQL_ONFAIL_CLAUSE and has the reverse meaning. You can
350 +declare triggers in the authmysqlrc configuration file. They can be used to
351 +arrange some logging facility in the database or just to keep last times
352 +of the successful/failed login tries. The typical trigger, which puts last
353 +login date into the users' table can look like this:
355 +MYSQL_ONSUCCESS_CLAUSE UPDATE users SET last_login=CURRENT_TIMESTAMP \
356 + WHERE username='$(username)';
358 +or, if you would like to know about last login failure for users you can try:
360 +MYSQL_ONFAIL_CLAUSE UPDATE users SET last_bad_login=CURRENT_TIMESTAMP \
361 + WHERE username='$(username)';
363 -Courier-imap-myownquery.patch allows administrator to set own MySQL queries
364 -used by authdaemon to authenticate user (including fetchig credentials) and to
365 -change user's password. It allows to construct SELECT or UPDATE clause in the
366 -configuration file (authmysqlrc) by adding two new configuration variables:
367 -MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. It may be useful in the mail
368 -environments where there is such a need to have different database structure
369 -and/or tables scheme than expected by authmysql module.
370 +Note, that YOU CAN use the triggers even if you aren't using
371 +MYSQL_SELECT_CLAUSE. Also note, that there is such a possibility that ONFAIL
372 +trigger may be performed without a proper username. Take it into consideration
373 +when creating queries to avoid messy data on INSERT operations.
375 -It also implements a small parsing engine for substitution variables which
376 -may appear in the clauses and are used to put informations like username
377 -or domain into the right place of a query.
379 -This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
384 + *-----------------------
385 + 4 Examples of usage
386 + *-----------------------
388 +The "ownquery" feature gives you possibility to adapt an authentication query
389 +to the database. So the first thing you have to do is to design the database
390 +structure you need, whithout being grieved at what structure authentication
391 +routines like. You have to take care about four essential things:
395 + o The users' data in the database
397 + o The proper directories for keeping virtual mailboxes and a system user
398 + which can read and write them
400 + o The proper MySQL queries in your authmysqlrc configuration file
402 +4.1 corporate mail system
404 +This example is concerned about a corporate mail system with a small
405 +ammount of served virtual domains. The database scheme was derived from tpop3d
406 +documentation and modified a bit.
408 +4.1.1 database structure
410 +Our goal here is to separate the data responsible for keeping mailbox
411 +credentials from the data, which describes a domain.
413 +Let's create some tables for our example, filled up with an example data:
417 +purpose: associates virtual domain with domain name and informations
418 + necessary to access mailboxes withing the domain
420 +fields: domain_name - fully qualified domain name
421 + path_prefix - absolute pathname which points to
422 + a directory where domain's mailboxes
424 + quota - default quota for each mailbox
425 + uid - UID used to work on mailboxes
426 + gid - GID used to work on mailboxes
428 + +----------------+-------------+-----+-----+----------+
429 + | domain_name | path_prefix | uid | gid | quota |
430 + +----------------+-------------+-----+-----+----------+
431 + | exampledom.com | /var/mail/x | 555 | 555 | 10000000 |
432 + | pld.org.pl | /var/mail/p | 556 | 556 | 20000000 |
433 + | pld.net.pl | /var/mail/p | 556 | 556 | 20000000 |
434 + +----------------+-------------+-----+-----+----------+
438 +purpose: associates virtual mailbox with user and domain name,
439 + and with informations necessary to access mailbox
441 +fields: username - user login name (mailbox name)
442 + domain_name - fully qualified domain name
443 + mailbox_path - relative pathname for mailbox
444 + (will be appended to the path_prefix
445 + from domain_auth table to specify
446 + user's mailbox location)
447 + cryptpw - crypted password
448 + plainpw - plaintext password
450 + +----------+----------------+--------------+------------+--------+
451 + | username | domain_name | mailbox_path | cryptpw | plainpw |
452 + +----------+----------------+--------------+-----------+---------+
453 + | siefca | pld.org.pl | s/siefca | $1$fs45.. | dupa.8 |
454 + | siefca | pld.net.pl | s/siefca | $1$fs45.. | dupa.8 |
455 + | f00bar | exampledom.com | foobar | $1$g44w.. | secret |
456 + +----------+----------------+--------------+-----------+---------+
458 +Using MySQL monitor you can create these tables entering CREATE sequences.
459 +Be sure to connect to the database using administrative MySQL account
460 +(usualy: mysql -u mysql -p).
462 +--------------------- cut here
464 +# Create the database called vmail.
466 +CREATE database vmail;
468 +# Create an example MySQL user, which can read, write and delete data from
469 +# vmail database. Username: vuser Password: secret_password
471 +GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
473 + IDENTIFIED BY 'secret_password';
477 +# Create the tables.
481 +CREATE TABLE domains (
482 + domain_name char(255) DEFAULT '',
483 + path_prefix char(255) DEFAULT '' NOT NULL,
484 + uid int(10) unsigned DEFAULT '15000' NOT NULL,
485 + gid int(10) unsigned DEFAULT '15000' NOT NULL,
486 + quota char(255) DEFAULT '2000000' NOT NULL,
487 + KEY domain_name (domain_name(255))
490 +CREATE TABLE users (
491 + username char(128) DEFAULT '' NOT NULL,
492 + domain_name char(255) DEFAULT '',
493 + mailbox_path char(255) DEFAULT '' NOT NULL,
494 + cryptpw char(128) DEFAULT '' NOT NULL,
495 + clearpw char(128) DEFAULT '' NOT NULL,
496 + KEY username (username(128))
499 +# Create an example virtual domain entry
500 +# name : exampledom.com
503 +# path : /var/mail/x
504 +# quota : 10 Megs per mailbox
506 +INSERT INTO domains VALUES ('exampledom.com', '/var/mail/x', 555, 555,
509 +# Create an example virtual user entry
511 +# domain name : exampledom.com
512 +# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
514 +# mailbox path : s/siefca
516 +INSERT INTO users VALUES ('siefca', 'exampledom.com', 's/siefca',
517 + '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
520 +--------------------- cut here
522 +Note: If you would like to have your passwords more safe then just omit the
523 + clearpw column and put '' into the config-query in its place while
524 + doing SELECT on a database. But be ware - you'll be unable to use
525 + authentication methods which needs it, like MD5_CRAM.
527 +4.1.2 authdaemon configuration
529 +When our database is ready we can set up the configuration. :-) Go to
530 +authmysqlrc file and edit it.
532 +At the beginning we should take care about general informations, which
533 +are identifying our database:
535 +MYSQL_SERVER localhost
536 +MYSQL_USERNAME vuser
537 +MYSQL_PASSWORD secret_password
538 +MYSQL_DATABASE vmail
540 +Then we should add a clause responsible for authenticating user and
541 +fetching credentials:
543 +DEFAULT_DOMAIN exampledom.com
545 +MYSQL_SELECT_CLAUSE SELECT \
546 + users.username, users.cryptpw, users.clearpw, \
547 + domains.uid, domains.gid, \
548 + CONCAT_WS('/',domains.path_prefix,users.mailbox_path), \
549 + '', domains.quota, '' \
550 + FROM users, domains \
551 + WHERE domains.domain_name='$(domain)' \
552 + AND users.username='$(local_part)' \
553 + AND domains.domain_name=users.domain_name
556 +Note the '' in the place of field which tells where user's INBOX resides
557 +and in place of realname field. You should use '' if you want to put an empty
558 +value as a query result for some field.
560 +We also should add some configuration for changing user's password:
562 +MYSQL_CHPASS_CLAUSE UPDATE \
564 + SET clearpw='$(newpass)', \
565 + cryptpw='$(newpass_crypt)' \
566 + WHERE username='$(local_part)' \
567 + AND domain_name='$(domain)'
570 +Create a system user/group and a proper directory structure. In our example:
572 +groupadd -g 555 xdomain
573 +useradd -u 555 -g 555 xdomain
574 +mkdir -p /var/mail/x/s/siefca
575 +chmod -R 0770 /var/mail/x
576 +maildirmake /var/mail/x/s/siefca/Maildir
577 +chown -R xdomain.xdomain /var/mail/x
579 +Now, restart the authdaemon and see if it works. Try: telnet 0 pop3
586 +You should get Ok response. ;)
588 +4.2 virtual mail domains provider
590 +Let's consider more complicated database scheme, where there is a need to
591 +associate a lot of information with the domain name, including registrant
592 +information, owner, etc. That implies data separation between domain name,
593 +user and domain additional informations (which are unwanted when
594 +authentication process takes place). By proper data separation I mean
595 +avoiding unwanted redundancy in the database.
597 +Currently applied example doesn't care about the update password problem.
598 +This is due to current abilities of MySQL and authdaemon (authmysql).
599 +MySQL doesn't support subsequent SELECTs on UPDATE operation, and authmysql
600 +doesn't supports batched queries at the moment.
602 +4.2.1 database structure
606 +purpose: associates domain_id with domain name
608 +fields: domain_name - fully qualified domain name
609 + domain_id - domain identifier
611 + +----------------+-----------+
612 + | domain_name | domain_id |
613 + +----------------+-----------+
614 + | exampledom.com | 1 |
617 + | foobare.net.uk | 3 |
618 + +----------------+-----------+
620 +Note, that for pld.org.pl and pld.net.pl the domain identifiers are the same.
621 +We can create a domain aliases in such a way. :)
625 +purpose: associates domain_id with authentication credentials
626 + which are common for all users in the virtual domain
628 +fields: domain_id - domain identifier
629 + path_prefix - absolute pathname which points to
630 + a directory where domain's mailboxes
632 + quota - default quota for each mailbox
633 + uid - UID used to work on mailboxes
634 + gid - GID used to work on mailboxes
636 + +------------+---------------+--------+-------+-------+
637 + | domain_id | path_prefix | quota | uid | gid |
638 + +------------+---------------+--------+-------+-------+
639 + | 1 | /var/mail/ex | 100000 | 15000 | 15000 |
640 + | 2 | /var/mail/pld | 555500 | 15001 | 15000 |
641 + | 3 | /home/f0/mail | 8000 | 15002 | 15000 |
642 + +------------+---------------+--------+-------+-------+
646 +purpose: associates domain_id with additional informations
648 +fields: domain_id - domain identifier
649 + registrant_id - registrant identifier
650 + nic_handle - NIC handle
651 + owner_id - domain's owner identifier
652 + expires - domain's expiration date
654 + +------------+---------------+------------+----------+---------+
655 + | domain_id | registrant_id | nic_handle | owner_id | expires |
656 + +------------+---------------+------------+----------+---------+
658 + (we don't need to say anything more about this table indeed)
662 +purpose: associates users' identifiers with domains' identifiers
663 + and infers the credentials for various virtual mailboxes
665 +fields: username - user's login name
666 + domain_id - domain identifier
667 + cryptpw - crypted password
668 + plainpw - plaintext password
669 + quota - user's mailbox quota
670 + (will override quota value set for
671 + the whole virtual domain)
672 + path - relative pathname for mailbox
673 + (will be appended to the path_prefix
674 + from domain_auth table to specify
675 + user's mailbox location)
677 + +------------+-----------+----------+-----------+-------+------------+
678 + | username | domain_id | cryptpw | plainpw | quota | path |
679 + +------------+-----------+----------+-----------+-------+------------+
680 + | foobar | 1 | $1$hlIeE | dupa.8 | NULL | f/o/foobar |
681 + | breeder | 2 | $1$TWsdf | ziarno128 | 77777 | brd |
682 + +------------+-----------+----------+-----------+-------+------------+
684 + (you can add a realname column here, it doesn't fit to my terminal window:)
686 +--------------------- cut here
688 +# Create the database called vmail.
690 +CREATE database vmail;
692 +# Create an example MySQL user, which can read, write and delete data from
693 +# vmail database. Username: vuser Password: secret_password
695 +GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
697 + IDENTIFIED BY 'secret_password';
701 +# Create the tables.
705 +CREATE TABLE domain_names (
706 + domain_id int(10) unsigned NOT NULL,
707 + domain_name char(255) DEFAULT '' NOT NULL,
708 + KEY domain_name (domain_name(255))
711 +CREATE TABLE domain_auth (
712 + domain_id int(10) unsigned DEFAULT 1 NOT NULL,
713 + uid int(10) unsigned DEFAULT '15000' NOT NULL,
714 + gid int(10) unsigned DEFAULT '15000' NOT NULL,
715 + path_prefix char(255) DEFAULT '' NOT NULL,
716 + quota char(255) DEFAULT '20000000' NOT NULL,
717 + KEY domain_id (domain_id)
720 +CREATE TABLE users (
721 + username char(128) DEFAULT '' NOT NULL,
722 + domain_id int(10) unsigned DEFAULT 1 NOT NULL,
723 + cryptpw char(128) DEFAULT '' NOT NULL,
724 + plainpw char(128) DEFAULT '' NOT NULL,
725 + name char(128) DEFAULT '' NOT NULL,
727 + path char(255) DEFAULT '' NOT NULL,
728 + KEY username (username(128))
731 +# Create an example virtual domain entry
733 +# name : exampledom.com
736 +# path : /var/mail/example
737 +# quota : 20 Megs per mailbox
739 +INSERT INTO domain_names VALUES (1, 'exampledom.com');
740 +INSERT INTO domain_auth VALUES (1, '15000', '15000', '/var/mail/example',
743 +# Create an example virtual user entry
745 +# domain id : 1 (points to exampledom.com)
746 +# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
749 +# quota : NULL (we want it to be fetched from domain_auth table)
750 +# mailbox path : s/i/siefca
752 +INSERT INTO users VALUES ('siefca', 1, '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
753 + 'dupa.8', 'Pawel Wilk', NULL, 's/i/siefca');
755 +--------------------- cut here
757 +Ok, we've done what we need. Don't forget to create system user with UID and
758 +GID set to 15000, and a directory containing mailboxes (in this case:
759 +/var/mail/example) owned by system user I've mentioned above.
760 +There is also necessary to create Maildir folder structure for our user
761 +inside the virtual domain directory - you can configure your MTA agent to do
762 +such thing when first message arrive or use maildirmake tool, which comes
766 +4.2.2 authdaemon configuration
768 +DEFAULT_DOMAIN exampledom.com
770 +MYSQL_SELECT_CLAUSE SELECT \
776 + CONCAT_WS('/',domain_auth.path_prefix,users.path), \
778 + IFNULL(users.quota, domain_auth.quota), \
780 + FROM users, domain_names, domain_auth \
781 + WHERE domain_names.domain_name='$(domain)' \
782 + AND users.username='$(local_part)' \
783 + AND domain_names.domain_id=users.domain_id \
784 + AND domain_names.domain_id=domain_auth.domain_id
794 +/////////////////////////// PART II - Developer Notes /////////////////////////
796 *-----------------------
797 1 Modifications overview
798 *-----------------------
800 -Modified files: authmysqllib.c authmysqlrc
801 +Modified files: authmysqllib.c authmysql.c authmysql.h authmysqlrc
803 Each modified set of instructions is marked by my e-mail address:
806 -Changes in the current source code are related to:
807 +Changes in the source code are related to:
809 - sections where the queries are constructed
810 (including memory allocation for the buffers)
812 newline as the second is replaced by two whitespaces while
813 putting into the buffer
815 + i've also added USER_DOMAIN_CONCAT and USER_DOMAIN_SEPARATORS
816 + configuration options - they're used by get_localpart(), get_domain()
817 + and get_username() functions, which are described below
819 - sections where the query is constructed
821 selection is made, depending on configuration variables which
823 MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
826 -The last two definitions are just for code simplification.
827 +The last two definitions (SV_BEGIN_LEN and SV_END_LEN) are just for code
830 +#define DEF_CONCAT_STRING "@"
831 +#define DEF_SEPARATORS_SET "@%"
833 +The first (DEF_CONCAT_STRING) is used to set the defaults for a
834 +concatenation string, used when parsing $(username) substitution variable.
835 +The second (DEF_SEPARATORS_SET) is the set of characters, which are treated as
836 +separators when splitting local part from the domain.
841 In this example we've declared that $(some) in the query should be
842 replaced by 'replacement' text, and replacement for $(anotha) will
843 be defined in the code before passing on the array pointer to
844 -the paring function.
845 +the general parsing function.
848 3.2 typedef size_t (*parsefunc)
850 structure of var_data type, which contains variable definition
851 of a given name. It returns NULL on error or failure.
855 + authlib/authmysqllib.c
862 This function returns -1 if an error has occured and 0 if
863 everything went good.
867 + authlib/authmysqllib.c
870 4.3 ParsePlugin_counter
872 @@ -314,6 +1019,11 @@
873 This function returns the variable size or -1 if an error
874 has occured, 0 if everything went good.
878 + authlib/authmysqllib.c
881 4.4 ParsePlugin_builder
885 type pointer and refers to the (char *) pointer variable.
886 After each call it shifts the value of pointer variable (char *)
887 incrementing it by len bytes. Be careful when using this function
888 - - its changes the given pointer value. Always operate on an
889 + - it changes the given pointer value. Always operate on an
890 additional pointer type variable when passing it as the third
893 @@ -342,6 +1052,10 @@
894 This function returns the variable size or -1 if an error
895 has occured, 0 if everything went good.
899 + authlib/authmysqllib.c
908 - This function parses the string pointed with source according to the
909 + This function parses the string pointed to by source according to the
910 replacement instructions set in var_data array, which is passed with
911 its pointer vdt. It produces changed string located in newly allocated
913 @@ -377,6 +1091,10 @@
914 Function returns pointer to the result buffer or NULL
915 if an error has occured.
919 + authlib/authmysqllib.c
923 This function allocates some amount of memory using standard
924 @@ -405,6 +1123,10 @@
925 It returns a pointer to the static buffer which contains
926 validated password string or NULL if an error has occured.
930 + authlib/authmysqllib.c
935 @@ -414,20 +1136,28 @@
939 - static const char *get_localpart (const char *username);
940 + static const char *get_localpart (const char *username,
941 + const char *separators);
945 This function detaches local part of an e-mail address
946 from string pointed with username and puts it to the
947 buffer of the fixed length. All necessary cleaning is
948 - made on the result string.
949 + made on the result string. String pointed with separators
950 + refers to a set of characters, which are treated as
951 + separation signs between local part and a domain.
955 Pointer to the static buffer containing local part or
956 NULL if there was some error.
960 + authlib/authmysqllib.c
966 @@ -438,24 +1168,68 @@
969 static const char *get_domain (const char *username,
970 - const char *defdomain);
971 + const char *defdomain,
972 + const char *separators);
976 This function detaches domain part of an e-mail address
977 from string pointed with username and puts it to the
978 buffer of the fixed length. All necessary cleaning is
979 - made on the result string. If function cannot find domain
980 - part in the string the string pointed by defdomain is
982 + made on the result string. If the function cannot find a domain
983 + part in the string then the string pointed to by defdomain is
984 + used instead. If this function cannot find a domain part
985 + as well as it cannot obtain the default domain (it's empty string
986 + or the defdomain pointer is NULL) the returned result string is an
987 + empty string. The string pointed with separators refers to a set
988 + of characters, which are treated as separation signs between local
993 Pointer to the static buffer containing domain name or
994 NULL if there was some error.
998 + authlib/authmysqllib.c
1001 -4.9 parse_select_clause
1010 + static const char *get_username (const char *username,
1011 + const char *domainname,
1012 + const char *concat_str);
1016 + This function concatenates the localpart with a domain name
1017 + using the string pointed with concat_str. If the domain is
1018 + empty or NULL the result comes without binding string.
1022 + Pointer to the static buffer containing output string or
1023 + NULL if there was some error.
1027 + authlib/authmysqllib.c
1031 + This function does not any string cleaning, nor default domain
1032 + checking. It is designed to work on results of get_localpart() and
1036 +4.10 parse_select_clause
1040 @@ -465,7 +1239,9 @@
1042 static char *parse_select_clause (const char *clause,
1043 const char *username,
1044 - const char *defdomain);
1045 + const char *defdomain
1046 + const char *concat_str,
1047 + const char *separators_set);
1051 @@ -473,15 +1249,21 @@
1052 function. It parses a query pointed by caluse. username
1053 and defdomain strings are used to replace corresponding
1054 substitution strings if present in the query: $(local_part)
1056 + and $(domain). The separators_set is passed to get_username()
1057 + and get_domain() invocations, and the concat_str is passed
1058 + to get_username() function, which is responsible for replacing
1059 + $(username) substitution variable.
1064 Same as parse_string().
1068 + authlib/authmysqllib.c
1070 -4.10 parse_chpass_clause
1072 +4.11 parse_chpass_clause
1076 @@ -492,6 +1274,8 @@
1077 static char *parse_chpass_clause (const char *clause,
1078 const char *username,
1079 const char *defdomain,
1080 + const char *separators_set,
1081 + const char *concat_str,
1082 const char *newpass,
1083 const char *newpass_crypt);
1085 @@ -502,12 +1286,56 @@
1086 defdomain, newpass and newpass_crypt strings are used to
1087 replace corresponding substitution strings if present in
1088 the query: $(local_part), $(domain), $(newpass),
1090 + $(newpass_crypt). The separators_set and the concat_str
1091 + are passed to get_localpart(), get_domain(), and get_username()
1092 + functions as described in the entry for parse_select_clause().
1096 Same as parse_string().
1100 + authlib/authmysqllib.c
1103 +4.12 auth_mysql_on_trigger
1107 + auth_mysql_on_trigger
1111 + int auth_mysql_on_trigger (const char *clause_name,
1112 + const char *username);
1116 + This function is responsible for calling out the MySQL queries
1117 + depending on which authentication state was reached.
1119 + The clause_name should contain the name of a clause, which can be found
1120 + in the configuration file, and the username is simply the string used
1121 + as username (including the domain if entered).
1123 + This function reads DEFAULT_DOMAIN, USER_DOMAIN_CONCAT and
1124 + USER_DOMAIN_SEPARATORS from the configuration file using read_env(),
1125 + then it uses parse_select_clause() to parse the query obtained using
1126 + read_env(clause_name), and then it calls querying subroutines to
1127 + perform the action.
1131 + This function returns 1 on success and 0 on failure. The query results
1132 + are simply discarded. If a trigger's clause is not defined in the
1133 + configuration file the 1 is returned and function silently ends its
1138 + authlib/authmysql.h
1139 + authlib/authmysql.c
1143 @@ -520,11 +1348,9 @@
1144 strings after split (problem?)
1145 - allow admin to set a group name instead of numerical group id
1146 - allow admin to set a username instead of numerical user id
1150 - - MYSQL_PRESELECT_CLAUSE (query which comes before MYSQL_SELECT_CLAUSE)
1151 - - MYSQL_POSTSELECT_CLAUSE (query which comes after MYSQL_SELECT_CLAUSE)
1152 +- allow batched queries and register variables for keeping results
1153 +- put the parsing routines into separate files to make possible of sharing it
1154 + by more authentication modules
1158 @@ -534,10 +1360,20 @@
1160 *------------------------
1162 -At the beginning this patch was messy indeed. :> I would like to thank
1163 -Sam Varshavchik for pointing me a lot how to make it more fast and solid.
1164 -I would also thank Philip Hazel, Chris Lightfoot and Mike Bremford which
1165 -by their software capabilities inspired me to write it.
1166 +At the beginning the patch was messy indeed. :> I would like to thank:
1169 + for pointing me a lot, how to make it more fast and solid
1171 +Philip Hazel, Chris Lightfoot, Mike Bremford
1172 + which by their software's capabilities inspired me to write it
1175 + which remainded me to make the documentation more friendly for
1176 + those who are not programmers and just want to use it
1179 + for reviewing this document just before it was published
1181 ---------------------------------------------------------------------------
1183 diff -ur courier-imap-1.5.3.20020921.orig/authlib/authmysql.c courier-imap-1.5.3.20020921/authlib/authmysql.c
1184 --- courier-imap-1.5.3.20020921.orig/authlib/authmysql.c Mon Aug 19 17:52:28 2002
1185 +++ courier-imap-1.5.3.20020921/authlib/authmysql.c Sat Sep 28 00:01:07 2002
1187 if ((user=strtok(authdata, "\n")) == 0 ||
1188 (pass=strtok(0, "\n")) == 0)
1191 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1201 if (authcheckpassword(pass,authinfo->cryptpw))
1204 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1209 return (0); /* User/Password not found. */
1214 if (strcmp(pass, authinfo->clearpw))
1217 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1228 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1233 return (0); /* Username not found */
1236 @@ -132,6 +148,12 @@
1237 (*callback_func)(&aa, callback_arg);
1240 + if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
1246 return (strdup(authinfo->username));
1249 @@ -153,7 +175,11 @@
1251 if (authcheckpassword(pass,authinfo->cryptpw))
1254 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1259 return (-1); /* User/Password not found. */
1262 @@ -161,13 +187,21 @@
1264 if (strcmp(pass, authinfo->clearpw))
1267 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1278 + if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1286 @@ -176,6 +210,13 @@
1291 + if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
1300 diff -ur courier-imap-1.5.3.20020921.orig/authlib/authmysql.h courier-imap-1.5.3.20020921/authlib/authmysql.h
1301 --- courier-imap-1.5.3.20020921.orig/authlib/authmysql.h Mon Aug 6 05:12:39 2001
1302 +++ courier-imap-1.5.3.20020921/authlib/authmysql.h Sat Sep 28 00:01:07 2002
1306 extern struct authmysqluserinfo *auth_mysql_getuserinfo(const char *);
1307 +extern int auth_mysql_on_trigger (const char *clause_name, const char *username);
1308 extern void auth_mysql_cleanup();
1310 extern int auth_mysql_setpass(const char *, const char *);
1311 diff -ur courier-imap-1.5.3.20020921.orig/authlib/authmysqllib.c courier-imap-1.5.3.20020921/authlib/authmysqllib.c
1312 --- courier-imap-1.5.3.20020921.orig/authlib/authmysqllib.c Sun Aug 11 22:01:25 2002
1313 +++ courier-imap-1.5.3.20020921/authlib/authmysqllib.c Sat Sep 28 06:06:41 2002
1315 #define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
1316 #define SV_END_LEN ((sizeof(SV_END_MARK))-1)
1318 +#define DEF_CONCAT_STRING "@"
1319 +#define DEF_SEPARATORS_SET "@%"
1321 static const char rcsid[]="$Id$";
1323 /* siefca@pld.org.pl */
1328 - "\n", len, begin);
1329 + "\n", (int) len, begin);
1333 @@ -426,21 +429,43 @@
1342 /* siefca@pld.org.pl */
1343 -static const char *get_localpart (const char *username)
1344 +static const char *get_username (const char *username, const char *domainname,
1345 + const char *concat_str)
1347 +static char username_buf[400];
1349 + if (!username || !domainname || !concat_str ||
1350 + *username == '\0' || *concat_str == '\0') return NULL;
1351 + if (( strlen(username) +
1352 + strlen(concat_str) +
1353 + strlen(domainname)) > 397) return NULL;
1355 + if (*domainname == '\0')
1356 + strcpy (username_buf, username);
1358 + sprintf (username_buf, "%s%s%s", username, concat_str,
1361 + return (username_buf);
1364 +/* siefca@pld.org.pl */
1365 +static const char *get_localpart (const char *username, const char *separators)
1368 const char *l_end, *p;
1370 static char localpart_buf[130];
1372 - if (!username || *username == '\0') return NULL;
1373 + if (!username || *username == '\0' ||
1374 + !separators || *separators == '\0') return NULL;
1376 - p = strchr(username,'@');
1377 + p = strpbrk (username, separators);
1380 if ((p-username) > 128)
1381 @@ -469,21 +494,27 @@
1384 /* siefca@pld.org.pl */
1385 -static const char *get_domain (const char *username, const char *defdomain)
1386 +static const char *get_domain (const char *username, const char *defdomain,
1387 + const char *separators)
1389 static char domain_buf[260];
1393 - if (!username || *username == '\0') return NULL;
1394 - p = strchr(username,'@');
1395 + if (!username || *username == '\0' ||
1396 + !separators || *separators == '\0') return NULL;
1398 + p = strpbrk (username, separators);
1400 if (!p || *(p+1) == '\0')
1402 - if (defdomain && *defdomain)
1403 + if (defdomain && *defdomain != '\0')
1408 + *domain_buf = '\0';
1409 + return domain_buf;
1414 @@ -536,20 +567,27 @@
1416 /* siefca@pld.org.pl */
1417 static char *parse_select_clause (const char *clause, const char *username,
1418 - const char *defdomain)
1419 + const char *defdomain,
1420 + const char *concat_str,
1421 + const char *separators_set)
1423 static struct var_data vd[]={
1424 {"local_part", NULL, sizeof("local_part"), 0},
1425 {"domain", NULL, sizeof("domain"), 0},
1426 + {"username", NULL, sizeof("username"), 0},
1427 {NULL, NULL, 0, 0}};
1429 if (clause == NULL || *clause == '\0' ||
1430 - !username || *username == '\0')
1431 + !username || *username == '\0' ||
1432 + !concat_str || *concat_str == '\0' ||
1433 + !separators_set || *separators_set == '\0')
1436 - vd[0].value = get_localpart (username);
1437 - vd[1].value = get_domain (username, defdomain);
1438 - if (!vd[0].value || !vd[1].value)
1439 + vd[0].value = get_localpart (username, separators_set);
1440 + vd[1].value = get_domain (username, defdomain, separators_set);
1441 + vd[2].value = get_username (vd[0].value, vd[1].value, concat_str);
1443 + if (!vd[0].value || !vd[1].value || !vd[2].value)
1446 return (parse_string (clause, vd));
1447 @@ -557,12 +595,16 @@
1449 /* siefca@pld.org.pl */
1450 static char *parse_chpass_clause (const char *clause, const char *username,
1451 - const char *defdomain, const char *newpass,
1452 + const char *defdomain,
1453 + const char *separators_set,
1454 + const char *concat_str,
1455 + const char *newpass,
1456 const char *newpass_crypt)
1458 static struct var_data vd[]={
1459 {"local_part", NULL, sizeof("local_part"), 0},
1460 {"domain", NULL, sizeof("domain"), 0},
1461 + {"username", NULL, sizeof("username"), 0},
1462 {"newpass", NULL, sizeof("newpass"), 0},
1463 {"newpass_crypt", NULL, sizeof("newpass_crypt"), 0},
1464 {NULL, NULL, 0, 0}};
1465 @@ -570,19 +612,83 @@
1466 if (clause == NULL || *clause == '\0' ||
1467 !username || *username == '\0' ||
1468 !newpass || *newpass == '\0' ||
1469 + !separators_set || *separators_set == '\0' ||
1470 !newpass_crypt || *newpass_crypt == '\0') return NULL;
1472 - vd[0].value = get_localpart (username);
1473 - vd[1].value = get_domain (username, defdomain);
1474 - vd[2].value = validate_password (newpass);
1475 - vd[3].value = validate_password (newpass_crypt);
1476 + vd[0].value = get_localpart (username, separators_set);
1477 + vd[1].value = get_domain (username, defdomain, separators_set);
1478 + vd[3].value = get_username (vd[0].value, vd[1].value, concat_str);
1479 + vd[4].value = validate_password (newpass);
1480 + vd[5].value = validate_password (newpass_crypt);
1482 if (!vd[0].value || !vd[1].value ||
1483 - !vd[2].value || !vd[3].value) return NULL;
1484 + !vd[2].value || !vd[3].value ||
1485 + !vd[4].value || !vd[5].value) return NULL;
1487 return (parse_string (clause, vd));
1490 +/* siefca@pld.org.pl */
1491 +int auth_mysql_on_trigger (const char *clause_name, const char *username)
1493 +char *querybuf =NULL;
1494 +const char *concat_str =NULL,
1495 + *separators_set =NULL,
1500 + if (!clause_name || *clause_name == '\0') return (0);
1501 + on_clause = read_env (clause_name);
1502 + if (!on_clause || *on_clause == '\0') return (1);
1504 + defdomain = read_env ("DEFAULT_DOMAIN");
1505 + concat_str = read_env ("USER_DOMAIN_CONCAT");
1506 + separators_set = read_env ("USER_DOMAIN_SEPARATORS");
1507 + if (!defdomain) defdomain = "";
1508 + if (!concat_str || *concat_str == '\0')
1509 + concat_str = DEF_CONCAT_STRING;
1510 + if (!separators_set || *separators_set == '\0')
1511 + separators_set = DEF_SEPARATORS_SET;
1513 + querybuf = parse_select_clause (on_clause,
1519 + if (!querybuf) return (0);
1521 + if (mysql_query (mysql, querybuf))
1523 + /* <o.blasnik@nextra.de> */
1525 + auth_mysql_cleanup();
1533 + if (mysql_query (mysql, querybuf))
1536 + auth_mysql_cleanup();
1537 + /* Server went down, that's OK,
1538 + ** try again next time.
1544 + result = mysql_store_result(mysql);
1545 + if (result) mysql_free_result(result);
1551 struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username)
1553 const char *user_table =NULL;
1557 *where_clause =NULL,
1558 + *concat_str =NULL,
1559 + *separators_set =NULL,
1560 *select_clause =NULL; /* siefca@pld.org.pl */
1562 static const char query[]=
1563 @@ -709,7 +817,19 @@
1566 /* siefca@pld.org.pl */
1567 - querybuf=parse_select_clause (select_clause, username, defdomain);
1568 + concat_str = read_env ("USER_DOMAIN_CONCAT");
1569 + separators_set = read_env ("USER_DOMAIN_SEPARATORS");
1571 + if (!concat_str || *concat_str == '\0')
1572 + concat_str = DEF_CONCAT_STRING;
1573 + if (!separators_set || *separators_set == '\0')
1574 + separators_set = DEF_SEPARATORS_SET;
1576 + querybuf = parse_select_clause (select_clause,
1581 if (!querybuf) return 0;
1585 *where_clause =NULL,
1588 + *concat_str =NULL,
1589 + *separators_set =NULL,
1590 *chpass_clause =NULL; /* siefca@pld.org.pl */
1593 @@ -842,13 +964,22 @@
1597 + concat_str = read_env ("USER_DOMAIN_CONCAT");
1598 + separators_set = read_env ("USER_DOMAIN_SEPARATORS");
1600 + if (!concat_str || *concat_str == '\0')
1601 + concat_str = DEF_CONCAT_STRING;
1602 + if (!separators_set || *separators_set == '\0')
1603 + separators_set = DEF_SEPARATORS_SET;
1605 sql_buf=parse_chpass_clause(chpass_clause,
1617 diff -ur courier-imap-1.5.3.20020921.orig/authlib/authmysqlrc courier-imap-1.5.3.20020921/authlib/authmysqlrc
1618 --- courier-imap-1.5.3.20020921.orig/authlib/authmysqlrc Thu Apr 4 06:36:29 2002
1619 +++ courier-imap-1.5.3.20020921/authlib/authmysqlrc Sat Sep 28 02:46:41 2002
1624 # Copyright 2000 Double Precision, Inc. See COPYING for
1625 # distribution information.
1626 @@ -141,65 +141,99 @@
1628 # MYSQL_WHERE_CLAUSE server='mailhost.example.com'
1630 -##NAME: MYSQL_SELECT_CLAUSE:0
1633 -# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database,
1634 -# which is structuraly different from proposed. The fixed string will
1635 -# be used to do a SELECT operation on database, which should return fields
1636 -# in order specified bellow:
1638 -# username, cryptpw, uid, gid, clearpw, home, maildir, quota, fullname
1639 +##NAME: USER_DOMAIN_CONCAT:0
1641 -# Enabling this option causes ignorance of any other field-related
1642 -# options, excluding default domain.
1643 +# This is optional. Here, you can write the string used to concatenate
1644 +# username with domain part while expanding the $(username) substitution
1645 +# variable. If it's not set the '@' character is used.
1646 +# See README.authmysql.myownquery for more information
1648 -# There are two variables, which you can use. Substitution will be made
1649 -# for them, so you can put entered username (local part) and domain name
1650 -# in the right place of your query. These variables are:
1651 -# $(local_part) and $(domain)
1652 +# USER_DOMAIN_CONCAT @
1654 +##NAME: USER_DOMAIN_SEPARATORS:0
1656 -# If a $(domain) is empty (not given by the remote user) the default domain
1657 -# name is used in its place.
1658 +# This is optional. Using this option you can set the set of characters
1659 +# which are treated as separators when splitting entered username into the
1660 +# local part and the domain name. If it's not set the defaults @% are used,
1661 +# so the user can authenticate using user@domain or user%domain form.
1662 +# See README.authmysql.myownquery for more information
1664 -# This example is a little bit modified adaptation of vmail-sql
1666 +# USER_DOMAIN_SEPARATORS @%+
1668 +##NAME: MYSQL_SELECT_CLAUSE:0
1670 -# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
1671 -# CONCAT('{MD5}', popbox.password_hash), \
1672 -# popbox.clearpw, \
1675 -# CONCAT(domain.path, '/', popbox.mbox_name), \
1679 -# FROM popbox, domain \
1680 -# WHERE popbox.local_part = '$(local_part)' \
1681 -# AND popbox.domain_name = '$(domain)' \
1682 -# AND popbox.domain_name = domain.domain_name
1683 +# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database,
1684 +# which is structuraly different from proposed. You can type here your MySQL
1685 +# query, which will be used to fetch user's credentials, and which should
1686 +# return fields in order specified bellow:
1688 +# username, cryptpw, clearpw, uid, gid, home, maildir, quota, fullname
1690 +# Enabling this option causes ignorance of any other field-related options.
1692 +# There also are variables, which you can use. Substitution will be made
1693 +# for them, so you can pass currently entered username and a domain name
1694 +# up to the right place within your query. These variables are:
1695 +# $(local_part) , $(domain) , $(username)
1697 +# If a $(domain) is empty (not given by the remote user) the default domain
1698 +# name is used in its place. $(username) is a local part concatenated with
1699 +# domain name using symbol defined in USER_DOMAIN_CONCAT or '@' if this option
1701 +# See README.authmysql.myownquery for more information
1703 +# MYSQL_SELECT_CLAUSE SELECT \
1704 +# users.username, users.cryptpw, users.clearpw, \
1705 +# domains.uid, domains.gid, \
1706 +# CONCAT_WS('/',domains.path_prefix,users.mailbox_path), \
1707 +# '', domains.quota, '' \
1708 +# FROM users, domains \
1709 +# WHERE domains.domain_name='$(domain)' \
1710 +# AND users.username='$(local_part)' \
1711 +# AND domains.domain_name=users.domain_name
1713 ##NAME: MYSQL_CHPASS_CLAUSE:0
1716 # This is optional, MYSQL_CHPASS_CLAUSE can be set when you have a database,
1717 -# which is structuraly different from proposed. The fixed string will
1718 -# be used to do an UPDATE operation on database. In other words, it is
1719 -# used, when changing password.
1720 +# which is structuraly different from proposed. You can use it to set up
1721 +# a MySQL query used to change user's password.
1723 # There are four variables, which you can use. Substitution will be made
1724 -# for them, so you can put entered username (local part) and domain name
1725 -# in the right place of your query. There variables are:
1726 -# $(local_part) , $(domain) , $(newpass) , $(newpass_crypt)
1727 +# for them, so you can put the currently entered username and the domain name
1728 +# in the right place of your query. These variables are:
1729 +# $(local_part) , $(domain) , $(username) , $(newpass) , $(newpass_crypt)
1731 # If a $(domain) is empty (not given by the remote user) the default domain
1732 -# name is used in its place.
1733 -# $(newpass) contains plain password
1734 -# $(newpass_crypt) contains its crypted form
1736 -# MYSQL_CHPASS_CLAUSE UPDATE popbox \
1737 -# SET clearpw='$(newpass)', \
1738 -# password_hash='$(newpass_crypt)' \
1739 -# WHERE local_part='$(local_part)' \
1740 -# AND domain_name='$(domain)'
1741 +# name is used in its place. $(newpass) contains plain password and
1742 +# $(newpass_crypt) contains its crypted form.
1743 +# See README.authmysql.myownquery for more information
1745 +# MYSQL_CHPASS_CLAUSE UPDATE users \
1746 +# SET clearpw='$(newpass)', \
1747 +# cryptpw='$(newpass_crypt)' \
1748 +# WHERE username='$(local_part)' \
1749 +# AND domain_name='$(domain)'
1751 +##NAME: MYSQL_ONSUCCESS_CLAUSE:0
1754 +# This is optional, MYSQL_ONSUCCESS_CLAUSE is a trigger - the query is performed
1755 +# each time user has successfuly logged in.
1756 +# See README.authmysql.myownquery for more information
1758 +# MYSQL_ONSUCCESS_CLAUSE UPDATE users \
1759 +# SET last_ok=CURRENT_TIMESTAMP \
1760 +# WHERE username='$(local_part)' \
1761 +# AND domain_name='$(domain)'
1763 +##NAME: MYSQL_ONFAIL_CLAUSE:0
1766 +# This is optional, MYSQL_ONFAIL_CLAUSE is a trigger - the query is performed
1767 +# each time user has successfuly logged in.
1768 +# See README.authmysql.myownquery for more information
1770 +# MYSQL_ONFAIL_CLAUSE UPDATE users \
1771 +# SET last_fail=CURRENT_TIMESTAMP \
1772 +# WHERE username='$(local_part)' \
1773 +# AND domain_name='$(domain)'