Update changelog.
[hcoop/debian/courier-authlib.git] / README.authmysql.myownquery
1
2
3
4
5 Developer Notes for courier-imap-myownquery.patch
6
7
8
9
10 document version: 1.03
11 author: Pawel Wilk
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 0 What's that?
29
30 1 Modifications overview
31
32 2 Definitions
33
34 3 New data types
35 3.1 struct var_data
36 3.2 typedef size_t (*parsefunc)
37
38 4 New functions
39 4.1 get_variable
40 4.2 parse_core
41 4.3 ParsePlugin_counter
42 4.4 ParsePlugin_builder
43 4.5 parse_string
44 4.6 validate_password
45 4.7 get_localpart
46 4.8 get_domain
47 4.9 parse_select_clause
48 4.10 parse_chpass_clause
49
50 5 Ideas and TODO
51
52 6 Thanks
53
54
55
56
57 *-----------------------
58 0 What's that?
59 *-----------------------
60
61 Courier-imap-myownquery.patch allows administrator to set own SQL queries
62 used by authdaemon to authenticate user (including fetchig credentials) and to
63 change user's password. It allows to construct SELECT or UPDATE clause in the
64 configuration file (authmysqlrc or authpgsqlrc) by adding two new configuration
65 variables: MYSQL_SELECT_CLAUSE or PGSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE
66 or PGSQL_CHPASS_CLAUSE. It may be useful in the mail environments where there
67 is such a need to have different database structure and/or tables scheme than
68 expected by authmysql or authpgsql module.
69
70 It also implements a small parsing engine for substitution variables which
71 may appear in the clauses and are used to put informations like username
72 or domain into the right place of a query.
73
74 This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
75
76
77
78
79
80 *-----------------------
81 1 Modifications overview
82 *-----------------------
83
84 Modified files: authmysqllib.c authmysqlrc authpgsqllib.c authpgsqlrc
85
86 Each modified set of instructions is marked by my e-mail address:
87 siefca@pld.org.pl (for MySQL files) or tom@minnesota.com (for PostgreSQL files)
88
89 Changes in the current source code are related to:
90
91 - sections where the queries are constructed
92 (including memory allocation for the buffers)
93
94 when MYSQL_SELECT_CLAUSE or MYSQL_CHPASS_CLAUSE or
95 PGSQL_SELECT_CLAUSE or PGSQL_CHPASS_CLAUSE is
96 used then the query goes through the parsing functions
97 passing over current memory allocation and query construction
98 subroutines
99
100 - section where the configuration file is read
101
102 i've had to modify read_env() function to allow line breaks
103 - now each sequence of the backslash as a first character and
104 newline as the second is replaced by two whitespaces while
105 putting into the buffer
106
107 - sections where the query is constructed
108
109 selection is made, depending on configuration variables which
110 are set or not - if own query is used
111
112
113
114
115
116 *-----------------------
117 2 Definitions
118 *-----------------------
119
120 #define MAX_SUBSTITUTION_LEN 32
121 #define SV_BEGIN_MARK "$("
122 #define SV_END_MARK ")"
123 #define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
124 #define SV_END_LEN ((sizeof(SV_END_MARK))-1)
125
126 These definitions allows to change substitution marks in an easy way.
127 SV_BEGIN_MARK refers to sequence of characters treated as a prefix of
128 each substitution variable and SV_END_MARK refers to string which is
129 a closing suffix. If the expected substitution variable is called
130 'local_part' (without apostrophes) then '$(local_part)' is a valid
131 string representation for SV_BEGIN_MARK set to "$(" and SV_END_MARK to ")".
132 MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
133 identifier (name).
134
135 The last two definitions are just for code simplification.
136
137
138
139
140
141
142 *-----------------------
143 3 New data types
144 *-----------------------
145
146 This section describes new data type definitions and variables.
147
148 3.1 struct var_data
149
150 struct var_data {
151 const char *name;
152 const char *value;
153 const size_t size;
154 size_t value_length;
155 } ;
156
157 This structure holds information needed by parsing routines.
158 Using var_data array you may specify a set of string substitutions
159 which should be done while parsing a query. Last element in array
160 should have all fields set to zero (null).
161
162 name field - should contain substituted variable name
163 value - should contain string which replaces it
164 size - should contain string size including the last zero byte ('\0')
165 value_length - should be set to zero - it is used as a value size cache
166
167
168 explanation: size is used to increase speed of calculation proccess
169 value_length is used to cache length of a value during the
170 parsing subroutines - it helps when substitution variable
171 occures more than once within the query
172
173 Example:
174
175 struct var_data vdt[] = {
176 {"some", "replacement", sizeof("some"), 0},
177 {"anotha", NULL, sizeof("anotha"), 0},
178 {NULL, NULL, 0, 0}
179 };
180
181 In this example we've declared that $(some) in the query should be
182 replaced by 'replacement' text, and replacement for $(anotha) will
183 be defined in the code before passing on the array pointer to
184 the paring function.
185
186
187 3.2 typedef size_t (*parsefunc)
188
189 typedef int (*parsefunc)(const char *, size_t, void *);
190
191 This type definition refers to the function pointer, which is used
192 to pass plugin functions into the core parsing subroutine. This definition
193 is included to simplify the declaration of the parse_core() function.
194
195
196
197
198
199 *-----------------------
200 4 New functions
201 *-----------------------
202
203 This section describes added functions.
204
205 4.1 get_variable
206
207 NAME
208
209 get_variable
210
211 SYNOPSIS
212
213 static const struct var_data *get_variable (const char *begin,
214 size_t len,
215 struct var_data *vdt);
216
217 DESCRIPTION
218
219 This function searches an array pointed by vdt and tries to find
220 the substitution variable, which name is identified with begin
221 pointer and length of len bytes long.
222
223 This function is also responsible for updating length cache field
224 of vdt elements and validating requested variables.
225
226 This function repports errors by sending human readable
227 messages to the standard error stream.
228
229 RETURN VALUE
230
231 This function returns a pointer to the array element which is
232 structure of var_data type, which contains variable definition
233 of a given name. It returns NULL on error or failure.
234
235
236 4.2 parse_core
237
238 NAME
239
240 parse_core
241
242 SYNOPSIS
243 static int parse_core (const char *source, struct var_data *vdt,
244 parsefunc outfn, void *result);
245
246 DESCRIPTION
247
248 This is the parsing routine for query strings containing the
249 substitution variables. It reads the string pointed with source
250 and tries to catch a valid substitution variables or parts which
251 are plain text blocks. The main purpose of using this function
252 it to split source string into parts and for each part call
253 outfn() function. Those parts are substrings identified by
254 pointer to some element of the source string and size.
255 Those elements are the result of splitting source string into
256 logical parts: plain text substrings and substitution variables'
257 values. To get the values of any found substitution variables
258 parse_core() uses get_variable() function. To find places
259 where substitution variables occurs it uses strstr() function
260 in conjunction with SV_BEGIN_MARK and SV_END_MARK definitions.
261 It passes vdt structure pointer to get_variable() function is
262 it calls it.
263
264 outfn() function should be passed by its pointer which
265 refers to declaration:
266
267 int (*outfn) (const char *begin,
268 size_t string_length,
269 void *void_pointer);
270
271 Each time outfn() is called the result argument of parse_core()
272 is passed to the outfn() as a last argument (void_pointer).
273
274 Example:
275
276 Example string "$(local_part) AND $(domain)" will cause the
277 outfn() to be called 3 times. First time for a value of
278 $(local_part) substitution variable, second time
279 for " AND " string, and the last time for $(domain) variable's
280 value. Variables are passed to outfn() by their (found) values,
281 plain text blocks are passed as they appear.
282
283 This function repports errors by sending human readable
284 messages to the standard error stream.
285
286 RETURN VALUE
287
288 This function returns -1 if an error has occured and 0 if
289 everything went good.
290
291 4.3 ParsePlugin_counter
292
293 NAME
294
295 ParsePlugin_counter
296
297 SYNOPSIS
298
299 int ParsePlugin_counter (const char *begin, size_t len,
300 void *vp);
301
302 DESCRIPTION
303
304 This is parsing plugin function. It simply increments the value
305 found in the memory area pointed by vp. It assumes that
306 the memory area is allocated for the variable of size_t
307 type and that area was passed by (size_t *) pointer.
308 The value is incremented by len argument. Begin argument
309 is not used.
310
311 This function repports errors by sending human readable
312 messages to the standard error stream.
313
314 RETURN VALUE
315
316 This function returns the variable size or -1 if an error
317 has occured, 0 if everything went good.
318
319 4.4 ParsePlugin_builder
320
321 NAME
322
323 ParsePlugin_builder
324
325 SYNOPSIS
326
327 int ParsePlugin_builder (const char *begin, size_t len,
328 void *vp);
329
330 DESCRIPTION
331
332 This is parsing plugin function. It simply copies len bytes
333 of a string pointed by begin to the end of memory area pointed by
334 vp. It assumes that the area pointed by vp is passed by (char **)
335 type pointer and refers to the (char *) pointer variable.
336 After each call it shifts the value of pointer variable (char *)
337 incrementing it by len bytes. Be careful when using this function
338 - its changes the given pointer value. Always operate on an
339 additional pointer type variable when passing it as the third
340 argument.
341
342 RETURN VALUE
343
344 This function returns the variable size or -1 if an error
345 has occured, 0 if everything went good.
346
347 4.5 parse_string
348
349 NAME
350 parse_string
351
352 SYNOPSIS
353
354 static char *parse_string (const char *source, struct var_data *vdt);
355
356 DESCRIPTION
357
358 This function parses the string pointed with source according to the
359 replacement instructions set in var_data array, which is passed with
360 its pointer vdt. It produces changed string located in newly allocated
361 memory area.
362
363 This function calls parse_core() function with various parsing
364 subroutines passed as function pointers.
365
366 1. It uses parse_core() with ParsePlugin_counter to obtain the
367 total amount of memory needed for the output string.
368
369 2. It allocates the memory.
370
371 3. It uses parse_core() with ParsePlugin_builder to build the
372 output string.
373
374 This function repports errors by sending human readable
375 messages to the standard error stream.
376
377 RETURN VALUE
378
379 Function returns pointer to the result buffer or NULL
380 if an error has occured.
381
382 WARNINGS
383
384 This function allocates some amount of memory using standard
385 ANSI C routines. Memory allocated by this function should be
386 freed with free().
387
388
389 4.6 validate_password
390
391 NAME
392 validate_password
393
394 SYNOPSIS
395
396 static const char *validate_password (const char *password);
397
398 DESCRIPTION
399
400 This function checks whether password string does contain
401 any dangerous characters, which may be used to pass command
402 strings to the database connection stream. If it founds one
403 it replaces it by the backslash character.
404
405 RETURN VALUE
406
407 It returns a pointer to the static buffer which contains
408 validated password string or NULL if an error has occured.
409
410
411 4.7 get_localpart
412
413 NAME
414
415 get_localpart
416
417 SYNOPSIS
418
419 static const char *get_localpart (const char *username);
420
421 DESCRIPTION
422
423 This function detaches local part of an e-mail address
424 from string pointed with username and puts it to the
425 buffer of the fixed length. All necessary cleaning is
426 made on the result string.
427
428 RETURN VALUE
429
430 Pointer to the static buffer containing local part or
431 NULL if there was some error.
432
433
434 4.8 get_domain
435
436 NAME
437
438 get_domain
439
440 SYNOPSIS
441
442 static const char *get_domain (const char *username,
443 const char *defdomain);
444
445 DESCRIPTION
446
447 This function detaches domain part of an e-mail address
448 from string pointed with username and puts it to the
449 buffer of the fixed length. All necessary cleaning is
450 made on the result string. If function cannot find domain
451 part in the string the string pointed by defdomain is
452 used instead.
453
454 RETURN VALUE
455
456 Pointer to the static buffer containing domain name or
457 NULL if there was some error.
458
459
460 4.9 parse_select_clause
461
462 NAME
463
464 parse_select_clause
465
466 SYNOPSIS
467
468 static char *parse_select_clause (const char *clause,
469 const char *username,
470 const char *defdomain);
471
472 DESCRIPTION
473
474 This function is a simple wrapper to the parse_string()
475 function. It parses a query pointed by caluse. username
476 and defdomain strings are used to replace corresponding
477 substitution strings if present in the query: $(local_part)
478 and $(domain).
479
480
481 RETURN VALUE
482
483 Same as parse_string().
484
485
486 4.10 parse_chpass_clause
487
488 NAME
489
490 parse_chpass_clause
491
492 SYNOPSIS
493
494 static char *parse_chpass_clause (const char *clause,
495 const char *username,
496 const char *defdomain,
497 const char *newpass,
498 const char *newpass_crypt);
499
500 DESCRIPTION
501
502 This function is a simple wrapper to the parse_string()
503 function. It parses a query pointed by caluse. username,
504 defdomain, newpass and newpass_crypt strings are used to
505 replace corresponding substitution strings if present in
506 the query: $(local_part), $(domain), $(newpass),
507 $(newpass_crypt).
508
509 RETURN VALUE
510
511 Same as parse_string().
512
513
514
515
516
517 *------------------------
518 5 Ideas and TODO
519 *------------------------
520
521 - solve problem with fixed buffer length of local part and the domain part
522 strings after split (problem?)
523 - allow admin to set a group name instead of numerical group id
524 - allow admin to set a username instead of numerical user id
525
526 - add clauses:
527
528 - MYSQL_PRESELECT_CLAUSE (query which comes before MYSQL_SELECT_CLAUSE)
529 - MYSQL_POSTSELECT_CLAUSE (query which comes after MYSQL_SELECT_CLAUSE)
530 - PGSQL_PRESELECT_CLAUSE (query which comes before PGSQL_SELECT_CLAUSE)
531 - PGSQL_POSTSELECT_CLAUSE (query which comes after PGSQL_SELECT_CLAUSE)
532
533
534
535
536
537 *------------------------
538 6 Thanks
539 *------------------------
540
541 At the beginning this patch was messy indeed. :> I would like to thank
542 Sam Varshavchik for pointing me a lot how to make it more fast and solid.
543 I would also thank Philip Hazel, Chris Lightfoot and Mike Bremford which
544 by their software capabilities inspired me to write it.
545
546 Thomas T. Thai <tom@minnesota.com> ported author's original MySQL code
547 to the PostgreSQL module.
548
549 ---------------------------------------------------------------------------
550