]> git.pld-linux.org Git - packages/courier-imap.git/blame - courier-imap-1.5.3.20020921-myownquery.patch
- upgrade to 1.7.0
[packages/courier-imap.git] / courier-imap-1.5.3.20020921-myownquery.patch
CommitLineData
e781919f 1diff -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
4@@ -2,13 +2,18 @@
5
6
7
8- Developer Notes for courier-imap-myownquery.patch
9+ Developer Notes and Usage Instructions
10+
11+ of
12+
13+ courier-imap-authmysql-myownquery
14
15
16
17+ document version: 1.30
18+ patch for version: 1.5.3.20020921
19+ author: Pawel Wilk <siefca@kernel.pl>
20
21- document version: 1.03
22- author: Pawel Wilk
23
24
25
26@@ -21,71 +26,749 @@
27
28
29
30+PART I - Usage Instructions
31
32+ 1 What's that?
33+
34+ 2 When will I need it?
35+
36+ 3 How does it work?
37+ 3.1 configuration variables
38+ 3.2 queries
39+ 3.3 substitutions
40+ 3.4 triggers
41+
42+ 4 Examples of usage
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
49+
50+PART II - Developer Notes
51+
52+ 1 Modifications overview
53+
54+ 2 Definitions
55+
56+ 3 New data types
57+ 3.1 struct var_data
58+ 3.2 typedef size_t (*parsefunc)
59+
60+ 4 New functions
61+ 4.1 get_variable
62+ 4.2 parse_core
63+ 4.3 ParsePlugin_counter
64+ 4.4 ParsePlugin_builder
65+ 4.5 parse_string
66+ 4.6 validate_password
67+ 4.7 get_localpart
68+ 4.8 get_domain
69+ 4.9 get_username
70+ 4.10 parse_select_clause
71+ 4.11 parse_chpass_clause
72+ 4.12 auth_mysql_on_trigger
73
74+ 5 Ideas and TODO
75
76+ 6 Thanks
77
78-0 What's that?
79
80-1 Modifications overview
81
82-2 Definitions
83
84-3 New data types
85- 3.1 struct var_data
86- 3.2 typedef size_t (*parsefunc)
87-
88-4 New functions
89- 4.1 get_variable
90- 4.2 parse_core
91- 4.3 ParsePlugin_counter
92- 4.4 ParsePlugin_builder
93- 4.5 parse_string
94- 4.6 validate_password
95- 4.7 get_localpart
96- 4.8 get_domain
97- 4.9 parse_select_clause
98- 4.10 parse_chpass_clause
99-
100-5 Ideas and TODO
101+//////////////////////////////// PART I - Usage ///////////////////////////////
102+
103+ *-----------------------
104+ 1 What's that?
105+ *-----------------------
106+
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.
114
115-6 Thanks
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.
118
119
120
121
122+
123+ *-----------------------
124+ 2 When will I need it?
125 *-----------------------
126- 0 What's that?
127+
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.
132+
133+ o When you have some great idea how to make the database structure
134+ more efficient due to your needs and your requirements.
135+
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. :)
139+
140+
141+
142+
143+
144 *-----------------------
145+ 3 How does it work?
146+ *-----------------------
147+
148+There are three things which the feature concerns:
149+
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
153+
154+3.1 configuration options
155+
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:
158+
159+MYSQL_SERVER (required)
160+MYSQL_USERNAME (required)
161+MYSQL_PASSWORD (required)
162+
163+ The server name, userid, and password used to log in.
164+
165+MYSQL_DATABASE (required)
166+
167+ The name of the MySQL database we will open.
168+
169+DEFAULT_DOMAIN (optional)
170+
171+ If DEFAULT_DOMAIN is defined, and someone tries to log in as
172+ 'user', we will look up 'user@DEFAULT_DOMAIN' instead.
173+
174+USER_DOMAIN_CONCAT (optional)
175+
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.
180+
181+USER_DOMAIN_SEPARATORS (optional)
182+
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
188+ authenticated.
189+
190+MYSQL_SELECT_CLAUSE (required)
191+MYSQL_CHPASS_CLAUSE (required under some circumstances)
192+
193+ These are the major options you should use. See 3.2 section
194+ for more info.
195+
196+MYSQL_ONSUCCESS_CLAUSE (optional)
197+MYSQL_ONFAIL_CLAUSE (optional)
198+
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.
205+
206+The options which have no effect, and may be safetly left blank are:
207+
208+MYSQL_USER_TABLE
209+MYSQL_CRYPT_PWFIELD
210+MYSQL_CLEAR_PWFIELD
211+MYSQL_UID_FIELD
212+MYSQL_GID_FIELD
213+MYSQL_LOGIN_FIELD
214+MYSQL_HOME_FIELD
215+MYSQL_NAME_FIELD
216+MYSQL_MAILDIR_FIELD
217+MYSQL_QUOTA_FIELD
218+MYSQL_WHERE_CLAUSE
219+
220+3.2 queries
221+
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
229+password.
230+
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:
234+
235+* username - which is the currently logged user's username (or the
236+ username with domain if you want it)
237+
238+* cryptpw - which is the user's crypted password
239+
240+* clearpw - which is the user's plaintext password
241+
242+* uid - which is a numerical UID value used as a process's UID when
243+ accessing the mailbox directory
244+
245+* gid - as above, but refers to GID
246+
247+* home - which contains full path to the user's home directory
248+
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
252+
253+quota - which describes a quota size for the mailbox
254+
255+fullname - which may contain the user's fullname
256+
257+(The fields marked by the asterix sign are required and cannot have an
258+ empty results)
259+
260+So, the typical query clause may start with:
261+
262+MYSQL_SELECT_CLAUSE SELECT \
263+ users.username, \
264+ users.cryptpw, \
265+ users.clearpw, \
266+ domains.uid, \
267+ domains.gid, \
268+ users.mailbox_path) \
269+ '' \
270+ domains.quota, \
271+ '' \
272+...
273+
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).
278+
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
283+in the database:).
284+
285+3.3 substitutions
286+
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.
296+
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.
300+
301+Allowed substitution variables:
302+
303+context: MYSQL_SELECT_CLAUSE, MYSQL_ONFAIL_CLAUSE, MYSQL_ONSUCCESS_CLAUSE
304+
305+$(local_part) will be replaced by currently verified user's username
306+ (without the domain part)
307+
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
312+
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
319+
320+context: MYSQL_CHPASS_CLAUSE
321+
322+$(local_part) will be replaced by currently verified user's username
323+ (without the domain part)
324+
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
329+
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
336+
337+$(newpass) will be replaced by currently authenticated user's
338+ new password to set up (plaintext password)
339+
340+$(newpass_crypt) will be replaced by currently authenticated user's
341+ new password to set up (MD5 form created from entered
342+ plain form)
343+
344+3.4 triggers
345+
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:
354+
355+MYSQL_ONSUCCESS_CLAUSE UPDATE users SET last_login=CURRENT_TIMESTAMP \
356+ WHERE username='$(username)';
357+
358+or, if you would like to know about last login failure for users you can try:
359+
360+MYSQL_ONFAIL_CLAUSE UPDATE users SET last_bad_login=CURRENT_TIMESTAMP \
361+ WHERE username='$(username)';
362
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.
374
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.
378
379-This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
380
381
382
383
384+ *-----------------------
385+ 4 Examples of usage
386+ *-----------------------
387+
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:
392+
393+ o The database
394+
395+ o The users' data in the database
396+
397+ o The proper directories for keeping virtual mailboxes and a system user
398+ which can read and write them
399+
400+ o The proper MySQL queries in your authmysqlrc configuration file
401+
402+4.1 corporate mail system
403+
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.
407+
408+4.1.1 database structure
409+
410+Our goal here is to separate the data responsible for keeping mailbox
411+credentials from the data, which describes a domain.
412+
413+Let's create some tables for our example, filled up with an example data:
414+
415+table: domains
416+
417+purpose: associates virtual domain with domain name and informations
418+ necessary to access mailboxes withing the domain
419+
420+fields: domain_name - fully qualified domain name
421+ path_prefix - absolute pathname which points to
422+ a directory where domain's mailboxes
423+ are located
424+ quota - default quota for each mailbox
425+ uid - UID used to work on mailboxes
426+ gid - GID used to work on mailboxes
427+
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+ +----------------+-------------+-----+-----+----------+
435+
436+table: users
437+
438+purpose: associates virtual mailbox with user and domain name,
439+ and with informations necessary to access mailbox
440+
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
449+
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+ +----------+----------------+--------------+-----------+---------+
457+
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).
461+
462+--------------------- cut here
463+
464+# Create the database called vmail.
465+
466+CREATE database vmail;
467+
468+# Create an example MySQL user, which can read, write and delete data from
469+# vmail database. Username: vuser Password: secret_password
470+
471+GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
472+ TO vuser@localhost
473+ IDENTIFIED BY 'secret_password';
474+
475+FLUSH PRIVILEGES;
476+
477+# Create the tables.
478+
479+use vmail;
480+
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))
488+ );
489+
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))
497+ );
498+
499+# Create an example virtual domain entry
500+# name : exampledom.com
501+# uid : 555
502+# gid : 555
503+# path : /var/mail/x
504+# quota : 10 Megs per mailbox
505+
506+INSERT INTO domains VALUES ('exampledom.com', '/var/mail/x', 555, 555,
507+ '10000000');
508+
509+# Create an example virtual user entry
510+# username : siefca
511+# domain name : exampledom.com
512+# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
513+# clearpw : dupa.8
514+# mailbox path : s/siefca
515+
516+INSERT INTO users VALUES ('siefca', 'exampledom.com', 's/siefca',
517+ '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
518+ 'dupa.8');
519+
520+--------------------- cut here
521+
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.
526+
527+4.1.2 authdaemon configuration
528+
529+When our database is ready we can set up the configuration. :-) Go to
530+authmysqlrc file and edit it.
531+
532+At the beginning we should take care about general informations, which
533+are identifying our database:
534+
535+MYSQL_SERVER localhost
536+MYSQL_USERNAME vuser
537+MYSQL_PASSWORD secret_password
538+MYSQL_DATABASE vmail
539+
540+Then we should add a clause responsible for authenticating user and
541+fetching credentials:
542+
543+DEFAULT_DOMAIN exampledom.com
544+
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
554+
555+
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.
559+
560+We also should add some configuration for changing user's password:
561+
562+MYSQL_CHPASS_CLAUSE UPDATE \
563+ users \
564+ SET clearpw='$(newpass)', \
565+ cryptpw='$(newpass_crypt)' \
566+ WHERE username='$(local_part)' \
567+ AND domain_name='$(domain)'
568+
569+And finally...
570+Create a system user/group and a proper directory structure. In our example:
571+
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
578+
579+Now, restart the authdaemon and see if it works. Try: telnet 0 pop3
580+
581+and type:
582+
583+USER siefca [ENTER]
584+PASS dupa.8 [ENTER]
585+
586+You should get Ok response. ;)
587+
588+4.2 virtual mail domains provider
589+
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.
596+
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.
601+
602+4.2.1 database structure
603+
604+table: domain_names
605+
606+purpose: associates domain_id with domain name
607+
608+fields: domain_name - fully qualified domain name
609+ domain_id - domain identifier
610+
611+ +----------------+-----------+
612+ | domain_name | domain_id |
613+ +----------------+-----------+
614+ | exampledom.com | 1 |
615+ | pld.org.pl | 2 |
616+ | pld.net.pl | 2 |
617+ | foobare.net.uk | 3 |
618+ +----------------+-----------+
619+
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. :)
622+
623+table: domain_auth
624+
625+purpose: associates domain_id with authentication credentials
626+ which are common for all users in the virtual domain
627+
628+fields: domain_id - domain identifier
629+ path_prefix - absolute pathname which points to
630+ a directory where domain's mailboxes
631+ are located
632+ quota - default quota for each mailbox
633+ uid - UID used to work on mailboxes
634+ gid - GID used to work on mailboxes
635+
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+ +------------+---------------+--------+-------+-------+
643+
644+table: domain_info
645+
646+purpose: associates domain_id with additional informations
647+
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
653+
654+ +------------+---------------+------------+----------+---------+
655+ | domain_id | registrant_id | nic_handle | owner_id | expires |
656+ +------------+---------------+------------+----------+---------+
657+
658+ (we don't need to say anything more about this table indeed)
659+
660+table: users
661+
662+purpose: associates users' identifiers with domains' identifiers
663+ and infers the credentials for various virtual mailboxes
664+
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)
676+
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+ +------------+-----------+----------+-----------+-------+------------+
683+
684+ (you can add a realname column here, it doesn't fit to my terminal window:)
685+
686+--------------------- cut here
687+
688+# Create the database called vmail.
689+
690+CREATE database vmail;
691+
692+# Create an example MySQL user, which can read, write and delete data from
693+# vmail database. Username: vuser Password: secret_password
694+
695+GRANT SELECT,INSERT,UPDATE,DELETE ON vmail.*
696+ TO vuser@localhost
697+ IDENTIFIED BY 'secret_password';
698+
699+FLUSH PRIVILEGES;
700+
701+# Create the tables.
702+
703+use vmail;
704+
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))
709+ );
710+
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)
718+ );
719+
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,
726+ quota char(255),
727+ path char(255) DEFAULT '' NOT NULL,
728+ KEY username (username(128))
729+ );
730+
731+# Create an example virtual domain entry
732+# id : 1
733+# name : exampledom.com
734+# uid : 15000
735+# gid : 15000
736+# path : /var/mail/example
737+# quota : 20 Megs per mailbox
738+
739+INSERT INTO domain_names VALUES (1, 'exampledom.com');
740+INSERT INTO domain_auth VALUES (1, '15000', '15000', '/var/mail/example',
741+ '20000000');
742+
743+# Create an example virtual user entry
744+# username : siefca
745+# domain id : 1 (points to exampledom.com)
746+# cryptpw : $1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/
747+# clearpw : dupa.8
748+# name : Pawel Wilk
749+# quota : NULL (we want it to be fetched from domain_auth table)
750+# mailbox path : s/i/siefca
751+
752+INSERT INTO users VALUES ('siefca', 1, '$1$wIfVZ8uK$qhagYAcIoZpQM83Et7c1e/',
753+ 'dupa.8', 'Pawel Wilk', NULL, 's/i/siefca');
754+
755+--------------------- cut here
756+
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
763+with Courier-IMAP.
764+
765+
766+4.2.2 authdaemon configuration
767+
768+DEFAULT_DOMAIN exampledom.com
769+
770+MYSQL_SELECT_CLAUSE SELECT \
771+ users.username, \
772+ users.cryptpw, \
773+ users.plainpw, \
774+ domain_auth.uid, \
775+ domain_auth.gid, \
776+ CONCAT_WS('/',domain_auth.path_prefix,users.path), \
777+ '', \
778+ IFNULL(users.quota, domain_auth.quota), \
779+ users.name \
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
785+
786+
787+.
788+.
789+.
790+.
791+.
792+.
793+
794+/////////////////////////// PART II - Developer Notes /////////////////////////
795
796 *-----------------------
797 1 Modifications overview
798 *-----------------------
799
800-Modified files: authmysqllib.c authmysqlrc
801+Modified files: authmysqllib.c authmysql.c authmysql.h authmysqlrc
802
803 Each modified set of instructions is marked by my e-mail address:
804 siefca@pld.org.pl
805
806-Changes in the current source code are related to:
807+Changes in the source code are related to:
808
809 - sections where the queries are constructed
810 (including memory allocation for the buffers)
811@@ -102,6 +785,10 @@
812 newline as the second is replaced by two whitespaces while
813 putting into the buffer
814
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
818+
819 - sections where the query is constructed
820
821 selection is made, depending on configuration variables which
822@@ -130,7 +817,16 @@
823 MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
824 identifier (name).
825
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
828+simplification.
829+
830+#define DEF_CONCAT_STRING "@"
831+#define DEF_SEPARATORS_SET "@%"
832+
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.
837
838
839
840@@ -179,7 +875,7 @@
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.
846
847
848 3.2 typedef size_t (*parsefunc)
849@@ -230,6 +926,10 @@
850 structure of var_data type, which contains variable definition
851 of a given name. It returns NULL on error or failure.
852
853+FILES
854+
855+ authlib/authmysqllib.c
856+
857
858 4.2 parse_core
859
860@@ -285,6 +985,11 @@
861
862 This function returns -1 if an error has occured and 0 if
863 everything went good.
864+
865+FILES
866+
867+ authlib/authmysqllib.c
868+
869
870 4.3 ParsePlugin_counter
871
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.
875
876+FILES
877+
878+ authlib/authmysqllib.c
879+
880+
881 4.4 ParsePlugin_builder
882
883 NAME
884@@ -333,7 +1043,7 @@
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
891 argument.
892
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.
896
897+FILES
898+
899+ authlib/authmysqllib.c
900+
901 4.5 parse_string
902
903 NAME
904@@ -353,7 +1067,7 @@
905
906 DESCRIPTION
907
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
912 memory area.
913@@ -377,6 +1091,10 @@
914 Function returns pointer to the result buffer or NULL
915 if an error has occured.
916
917+FILES
918+
919+ authlib/authmysqllib.c
920+
921 WARNINGS
922
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.
927
928+FILES
929+
930+ authlib/authmysqllib.c
931+
932
933 4.7 get_localpart
934
935@@ -414,20 +1136,28 @@
936
937 SYNOPSIS
938
939- static const char *get_localpart (const char *username);
940+ static const char *get_localpart (const char *username,
941+ const char *separators);
942
943 DESCRIPTION
944
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.
952
953 RETURN VALUE
954
955 Pointer to the static buffer containing local part or
956 NULL if there was some error.
957
958+FILES
959+
960+ authlib/authmysqllib.c
961+
962+
963
964 4.8 get_domain
965
966@@ -438,24 +1168,68 @@
967 SYNOPSIS
968
969 static const char *get_domain (const char *username,
970- const char *defdomain);
971+ const char *defdomain,
972+ const char *separators);
973
974 DESCRIPTION
975
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
981- used instead.
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
989+ part and a domain.
990
991 RETURN VALUE
992
993 Pointer to the static buffer containing domain name or
994 NULL if there was some error.
995
996+FILES
997+
998+ authlib/authmysqllib.c
999+
1000
1001-4.9 parse_select_clause
1002+4.9 get_username
1003+
1004+NAME
1005+
1006+ get_username
1007+
1008+SYNOPSIS
1009+
1010+ static const char *get_username (const char *username,
1011+ const char *domainname,
1012+ const char *concat_str);
1013+
1014+DESCRIPTION
1015+
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.
1019+
1020+RETURN VALUE
1021+
1022+ Pointer to the static buffer containing output string or
1023+ NULL if there was some error.
1024+
1025+FILES
1026+
1027+ authlib/authmysqllib.c
1028+
1029+WARNINGS
1030+
1031+ This function does not any string cleaning, nor default domain
1032+ checking. It is designed to work on results of get_localpart() and
1033+ get_domain().
1034+
1035+
1036+4.10 parse_select_clause
1037
1038 NAME
1039
1040@@ -465,7 +1239,9 @@
1041
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);
1048
1049 DESCRIPTION
1050
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)
1055- and $(domain).
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.
1060
1061-
1062 RETURN VALUE
1063
1064 Same as parse_string().
1065
1066+FILES
1067+
1068+ authlib/authmysqllib.c
1069
1070-4.10 parse_chpass_clause
1071+
1072+4.11 parse_chpass_clause
1073
1074 NAME
1075
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);
1084
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),
1089- $(newpass_crypt).
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().
1093
1094 RETURN VALUE
1095
1096 Same as parse_string().
1097
1098+FILES
1099+
1100+ authlib/authmysqllib.c
1101+
1102+
1103+4.12 auth_mysql_on_trigger
1104+
1105+NAME
1106+
1107+ auth_mysql_on_trigger
1108+
1109+SYNOPSIS
1110+
1111+ int auth_mysql_on_trigger (const char *clause_name,
1112+ const char *username);
1113+
1114+DESCRIPTION
1115+
1116+ This function is responsible for calling out the MySQL queries
1117+ depending on which authentication state was reached.
1118+
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).
1122+
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.
1128+
1129+RETURN VALUE
1130+
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
1134+ work.
1135+
1136+FILES
1137+
1138+ authlib/authmysql.h
1139+ authlib/authmysql.c
1140
1141
1142
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
1147-
1148-- add clauses:
1149-
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
1155
1156
1157
1158@@ -534,10 +1360,20 @@
1159 6 Thanks
1160 *------------------------
1161
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:
1167+
1168+Sam Varshavchik
1169+ for pointing me a lot, how to make it more fast and solid
1170+
1171+Philip Hazel, Chris Lightfoot, Mike Bremford
1172+ which by their software's capabilities inspired me to write it
1173+
1174+Oliver Oblasnik
1175+ which remainded me to make the documentation more friendly for
1176+ those who are not programmers and just want to use it
1177+
1178+Jacek Surazski
1179+ for reviewing this document just before it was published
1180
1181 ---------------------------------------------------------------------------
1182
1183diff -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
1186@@ -31,7 +31,11 @@
1187 if ((user=strtok(authdata, "\n")) == 0 ||
1188 (pass=strtok(0, "\n")) == 0)
1189 {
1190- errno=EPERM;
1191+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1192+ errno=EACCES;
1193+ else
1194+ errno=EPERM;
1195+
1196 return (0);
1197 }
1198
1199@@ -50,7 +54,11 @@
1200 {
1201 if (authcheckpassword(pass,authinfo->cryptpw))
1202 {
1203- errno=EPERM;
1204+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1205+ errno=EACCES;
1206+ else
1207+ errno=EPERM;
1208+
1209 return (0); /* User/Password not found. */
1210 }
1211 }
1212@@ -58,13 +66,21 @@
1213 {
1214 if (strcmp(pass, authinfo->clearpw))
1215 {
1216- errno=EPERM;
1217+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1218+ errno=EACCES;
1219+ else
1220+ errno=EPERM;
1221+
1222 return (0);
1223 }
1224 }
1225 else
1226 {
1227- errno=EPERM;
1228+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1229+ errno=EACCES;
1230+ else
1231+ errno=EPERM;
1232+
1233 return (0); /* Username not found */
1234 }
1235
1236@@ -132,6 +148,12 @@
1237 (*callback_func)(&aa, callback_arg);
1238 }
1239
1240+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
1241+ {
1242+ errno=EACCES;
1243+ return (0);
1244+ }
1245+
1246 return (strdup(authinfo->username));
1247 }
1248
1249@@ -153,7 +175,11 @@
1250 {
1251 if (authcheckpassword(pass,authinfo->cryptpw))
1252 {
1253- errno=EPERM;
1254+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1255+ errno=EACCES;
1256+ else
1257+ errno=EPERM;
1258+
1259 return (-1); /* User/Password not found. */
1260 }
1261 }
1262@@ -161,13 +187,21 @@
1263 {
1264 if (strcmp(pass, authinfo->clearpw))
1265 {
1266- errno=EPERM;
1267+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1268+ errno=EACCES;
1269+ else
1270+ errno=EPERM;
1271+
1272 return (-1);
1273 }
1274 }
1275 else
1276 {
1277- errno=EPERM;
1278+ if (!auth_mysql_on_trigger("MYSQL_ONFAIL_CLAUSE", user))
1279+ errno=EACCES;
1280+ else
1281+ errno=EPERM;
1282+
1283 return (-1);
1284 }
1285
1286@@ -176,6 +210,13 @@
1287 errno=EPERM;
1288 return (-1);
1289 }
1290+
1291+ if (!auth_mysql_on_trigger("MYSQL_ONSUCCESS_CLAUSE", user))
1292+ {
1293+ errno=EACCES;
1294+ return (-1);
1295+ }
1296+
1297 return (0);
1298 }
1299
1300diff -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
1303@@ -21,6 +21,7 @@
1304 } ;
1305
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();
1309
1310 extern int auth_mysql_setpass(const char *, const char *);
1311diff -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
1314@@ -24,6 +24,9 @@
1315 #define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
1316 #define SV_END_LEN ((sizeof(SV_END_MARK))-1)
1317
1318+#define DEF_CONCAT_STRING "@"
1319+#define DEF_SEPARATORS_SET "@%"
1320+
1321 static const char rcsid[]="$Id$";
1322
1323 /* siefca@pld.org.pl */
1324@@ -268,7 +271,7 @@
1325 SV_BEGIN_MARK
1326 "%.*s"
1327 SV_END_MARK
1328- "\n", len, begin);
1329+ "\n", (int) len, begin);
1330
1331 return NULL;
1332 }
1333@@ -426,21 +429,43 @@
1334 return NULL;
1335 }
1336 *pass_buf = '\0';
1337-
1338+
1339 return output_buf;
1340 }
1341
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)
1346+{
1347+static char username_buf[400];
1348+
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;
1354+
1355+ if (*domainname == '\0')
1356+ strcpy (username_buf, username);
1357+ else
1358+ sprintf (username_buf, "%s%s%s", username, concat_str,
1359+ domainname);
1360+
1361+ return (username_buf);
1362+}
1363+
1364+/* siefca@pld.org.pl */
1365+static const char *get_localpart (const char *username, const char *separators)
1366 {
1367 size_t lbuf = 0;
1368 const char *l_end, *p;
1369 char *q;
1370 static char localpart_buf[130];
1371
1372- if (!username || *username == '\0') return NULL;
1373+ if (!username || *username == '\0' ||
1374+ !separators || *separators == '\0') return NULL;
1375
1376- p = strchr(username,'@');
1377+ p = strpbrk (username, separators);
1378 if (p)
1379 {
1380 if ((p-username) > 128)
1381@@ -469,21 +494,27 @@
1382 }
1383
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)
1388 {
1389 static char domain_buf[260];
1390 const char *p;
1391 char *q;
1392
1393- if (!username || *username == '\0') return NULL;
1394- p = strchr(username,'@');
1395+ if (!username || *username == '\0' ||
1396+ !separators || *separators == '\0') return NULL;
1397+
1398+ p = strpbrk (username, separators);
1399
1400 if (!p || *(p+1) == '\0')
1401 {
1402- if (defdomain && *defdomain)
1403+ if (defdomain && *defdomain != '\0')
1404 return defdomain;
1405 else
1406- return NULL;
1407+ {
1408+ *domain_buf = '\0';
1409+ return domain_buf;
1410+ }
1411 }
1412
1413 p++;
1414@@ -536,20 +567,27 @@
1415
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)
1422 {
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}};
1428
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')
1434 return NULL;
1435
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);
1442+
1443+ if (!vd[0].value || !vd[1].value || !vd[2].value)
1444 return NULL;
1445
1446 return (parse_string (clause, vd));
1447@@ -557,12 +595,16 @@
1448
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)
1457 {
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;
1471
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);
1481
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;
1486
1487 return (parse_string (clause, vd));
1488 }
1489
1490+/* siefca@pld.org.pl */
1491+int auth_mysql_on_trigger (const char *clause_name, const char *username)
1492+{
1493+char *querybuf =NULL;
1494+const char *concat_str =NULL,
1495+ *separators_set =NULL,
1496+ *defdomain =NULL,
1497+ *on_clause =NULL;
1498+MYSQL_RES *result;
1499+
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);
1503+
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;
1512+
1513+ querybuf = parse_select_clause (on_clause,
1514+ username,
1515+ defdomain,
1516+ concat_str,
1517+ separators_set);
1518+
1519+ if (!querybuf) return (0);
1520+
1521+ if (mysql_query (mysql, querybuf))
1522+ {
1523+ /* <o.blasnik@nextra.de> */
1524+
1525+ auth_mysql_cleanup();
1526+
1527+ if (do_connect())
1528+ {
1529+ free(querybuf);
1530+ return (1);
1531+ }
1532+
1533+ if (mysql_query (mysql, querybuf))
1534+ {
1535+ free(querybuf);
1536+ auth_mysql_cleanup();
1537+ /* Server went down, that's OK,
1538+ ** try again next time.
1539+ */
1540+ return (1);
1541+ }
1542+ }
1543+ free(querybuf);
1544+ result = mysql_store_result(mysql);
1545+ if (result) mysql_free_result(result);
1546+
1547+ return (1);
1548+}
1549+
1550+
1551 struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username)
1552 {
1553 const char *user_table =NULL;
1554@@ -601,6 +707,8 @@
1555 *gid_field =NULL,
1556 *quota_field =NULL,
1557 *where_clause =NULL,
1558+ *concat_str =NULL,
1559+ *separators_set =NULL,
1560 *select_clause =NULL; /* siefca@pld.org.pl */
1561
1562 static const char query[]=
1563@@ -709,7 +817,19 @@
1564 else
1565 {
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");
1570+
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;
1575+
1576+ querybuf = parse_select_clause (select_clause,
1577+ username,
1578+ defdomain,
1579+ concat_str,
1580+ separators_set);
1581 if (!querybuf) return 0;
1582 }
1583
1584@@ -793,6 +913,8 @@
1585 *where_clause =NULL,
1586 *user_table =NULL,
1587 *login_field =NULL,
1588+ *concat_str =NULL,
1589+ *separators_set =NULL,
1590 *chpass_clause =NULL; /* siefca@pld.org.pl */
1591
1592 if (!mysql)
1593@@ -842,13 +964,22 @@
1594 }
1595 else
1596 {
1597+ concat_str = read_env ("USER_DOMAIN_CONCAT");
1598+ separators_set = read_env ("USER_DOMAIN_SEPARATORS");
1599+
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;
1604+
1605 sql_buf=parse_chpass_clause(chpass_clause,
1606 user,
1607 defdomain,
1608+ concat_str,
1609+ separators_set,
1610 pass,
1611 newpass_crypt_ptr);
1612 }
1613-
1614
1615 if (!sql_buf)
1616 {
1617diff -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
1620@@ -1,4 +1,4 @@
1621-##VERSION: $Id$
1622+##VERSION: $Id$
1623 #
1624 # Copyright 2000 Double Precision, Inc. See COPYING for
1625 # distribution information.
1626@@ -141,65 +141,99 @@
1627 #
1628 # MYSQL_WHERE_CLAUSE server='mailhost.example.com'
1629
1630-##NAME: MYSQL_SELECT_CLAUSE:0
1631-#
1632-# (EXPERIMENTAL)
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:
1637-#
1638-# username, cryptpw, uid, gid, clearpw, home, maildir, quota, fullname
1639+##NAME: USER_DOMAIN_CONCAT:0
1640 #
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
1647 #
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 @
1653+
1654+##NAME: USER_DOMAIN_SEPARATORS:0
1655 #
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
1663 #
1664-# This example is a little bit modified adaptation of vmail-sql
1665-# database scheme:
1666+# USER_DOMAIN_SEPARATORS @%+
1667+
1668+##NAME: MYSQL_SELECT_CLAUSE:0
1669 #
1670-# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
1671-# CONCAT('{MD5}', popbox.password_hash), \
1672-# popbox.clearpw, \
1673-# domain.uid, \
1674-# domain.gid, \
1675-# CONCAT(domain.path, '/', popbox.mbox_name), \
1676-# '', \
1677-# domain.quota, \
1678-# '', \
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:
1687+#
1688+# username, cryptpw, clearpw, uid, gid, home, maildir, quota, fullname
1689+#
1690+# Enabling this option causes ignorance of any other field-related options.
1691+#
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)
1696 #
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
1700+# is not set.
1701+# See README.authmysql.myownquery for more information
1702+#
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
1712+
1713 ##NAME: MYSQL_CHPASS_CLAUSE:0
1714 #
1715-# (EXPERIMENTAL)
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.
1722 #
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)
1730 #
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
1735-#
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
1744+#
1745+# MYSQL_CHPASS_CLAUSE UPDATE users \
1746+# SET clearpw='$(newpass)', \
1747+# cryptpw='$(newpass_crypt)' \
1748+# WHERE username='$(local_part)' \
1749+# AND domain_name='$(domain)'
1750+
1751+##NAME: MYSQL_ONSUCCESS_CLAUSE:0
1752+# (EXPERIMENTAL)
1753+#
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
1757+#
1758+# MYSQL_ONSUCCESS_CLAUSE UPDATE users \
1759+# SET last_ok=CURRENT_TIMESTAMP \
1760+# WHERE username='$(local_part)' \
1761+# AND domain_name='$(domain)'
1762+
1763+##NAME: MYSQL_ONFAIL_CLAUSE:0
1764+# (EXPERIMENTAL)
1765 #
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
1769+#
1770+# MYSQL_ONFAIL_CLAUSE UPDATE users \
1771+# SET last_fail=CURRENT_TIMESTAMP \
1772+# WHERE username='$(local_part)' \
1773+# AND domain_name='$(domain)'
This page took 0.239891 seconds and 4 git commands to generate.