]>
Commit | Line | Data |
---|---|---|
e781919f | 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 | |
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 | ||
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 | |
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 | ||
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 | |
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 *); | |
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 | |
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 | { | |
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 | |
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)' |