]> git.pld-linux.org Git - packages/courier-imap.git/blame - courier-imap-myownquery.patch
- myownquery.patch simplified according to suggestions from Sam Varshavchik
[packages/courier-imap.git] / courier-imap-myownquery.patch
CommitLineData
258494a2 1diff -Nur courier-imap-1.3.12.orig/authlib/README.myownquery courier-imap-1.3.12/authlib/README.myownquery
2--- courier-imap-1.3.12.orig/authlib/README.myownquery Thu Jan 1 01:00:00 1970
9e0529f5 3+++ courier-imap-1.3.12/authlib/README.myownquery Sun Dec 30 01:41:38 2001
4@@ -0,0 +1,543 @@
258494a2 5+
6+
7+
8+
9+ Developer Notes for courier-imap-myownquery.patch
10+
11+
12+
13+
9e0529f5 14+ document version: 1.03
258494a2 15+ author: Pawel Wilk
16+
17+
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
29+
30+
31+
32+0 What's that?
33+
34+1 Modifications overview
35+
36+2 Definitions
37+
38+3 New data types
39+ 3.1 struct var_data
40+ 3.2 typedef size_t (*parsefunc)
41+
42+4 New functions
9e0529f5 43+ 4.1 get_variable
44+ 4.2 parse_core
45+ 4.3 ParsePlugin_counter
46+ 4.4 ParsePlugin_builder
47+ 4.5 parse_string
48+ 4.6 validate_password
49+ 4.7 get_localpart
50+ 4.8 get_domain
51+ 4.9 parse_select_clause
52+ 4.10 parse_chpass_clause
258494a2 53+
54+5 Ideas and TODO
55+
9e0529f5 56+6 Thanks
258494a2 57+
58+
59+
60+
61+ *-----------------------
62+ 0 What's that?
63+ *-----------------------
64+
65+Courier-imap-myownquery.patch allows administrator to set own MySQL queries
66+used by authdaemon to authenticate user (including fetchig credentials) and to
67+change user's password. It allows to construct SELECT or UPDATE clause in the
68+configuration file (authmysqlrc) by adding two new configuration variables:
69+MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. It may be useful in the mail
70+environments where there is such a need to have different database structure
71+and/or tables scheme than expected by authmysql module.
72+
73+It also implements a small parsing engine for substitution variables which
74+may appear in the clauses and are used to put informations like username
75+or domain into the right place of a query.
76+
77+This patch was created using `diff -Nur` on courier-imap-1.3.12 source.
78+
79+
80+
81+
82+
83+ *-----------------------
84+ 1 Modifications overview
85+ *-----------------------
86+
87+Modified files: authmysqllib.c authmysqlrc
88+
89+Each modified set of instructions is marked by my e-mail address:
90+siefca@pld.org.pl
91+
92+Changes in the current source code are related to:
93+
94+- sections where the queries are constructed
95+ (including memory allocation for the buffers)
96+
97+ when MYSQL_SELECT_CLAUSE or MYSQL_CHPASS_CLAUSE is
98+ used then the query goes through the parsing functions
99+ passing over current memory allocation and query construction
100+ subroutines
101+
102+- section where the configuration file is read
103+
104+ i've had to modify read_env() function to allow line breaks
105+ - now each sequence of the backslash as a first character and
106+ newline as the second is replaced by two whitespaces while
107+ putting into the buffer
108+
109+- sections where the query is constructed
110+
111+ selection is made, depending on configuration variables which
112+ are set or not - if own query is used
113+
114+
115+
116+
117+
118+ *-----------------------
119+ 2 Definitions
120+ *-----------------------
121+
9e0529f5 122+#define MAX_SUBSTITUTION_LEN 32
123+#define SV_BEGIN_MARK "$("
124+#define SV_END_MARK ")"
125+#define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
126+#define SV_END_LEN ((sizeof(SV_END_MARK))-1)
258494a2 127+
128+These definitions allows to change substitution marks in an easy way.
129+SV_BEGIN_MARK refers to sequence of characters treated as a prefix of
130+each substitution variable and SV_END_MARK refers to string which is
131+a closing suffix. If the expected substitution variable is called
132+'local_part' (without apostrophes) then '$(local_part)' is a valid
133+string representation for SV_BEGIN_MARK set to "$(" and SV_END_MARK to ")".
9e0529f5 134+MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
135+identifier (name).
258494a2 136+
137+The last two definitions are just for code simplification.
138+
139+
140+
141+
142+
143+
144+ *-----------------------
145+ 3 New data types
146+ *-----------------------
147+
148+This section describes new data type definitions and variables.
149+
150+3.1 struct var_data
151+
152+struct var_data {
153+ const char *name;
154+ const char *value;
155+ const size_t size;
156+ size_t value_length;
157+ } ;
158+
159+This structure holds information needed by parsing routines.
160+Using var_data array you may specify a set of string substitutions
161+which should be done while parsing a query. Last element in array
162+should have all fields set to zero (null).
163+
164+name field - should contain substituted variable name
165+value - should contain string which replaces it
166+size - should contain string size including the last zero byte ('\0')
167+value_length - should be set to zero - it is used as a value size cache
168+
169+
170+explanation: size is used to increase speed of calculation proccess
171+ value_length is used to cache length of a value during the
172+ parsing subroutines - it helps when substitution variable
173+ occures more than once within the query
174+
175+Example:
176+
9e0529f5 177+struct var_data vdt[] = {
258494a2 178+ {"some", "replacement", sizeof("some"), 0},
179+ {"anotha", NULL, sizeof("anotha"), 0},
180+ {NULL, NULL, 0, 0}
181+};
182+
183+In this example we've declared that $(some) in the query should be
184+replaced by 'replacement' text, and replacement for $(anotha) will
185+be defined in the code before passing on the array pointer to
186+the paring function.
187+
188+
189+3.2 typedef size_t (*parsefunc)
190+
9e0529f5 191+typedef int (*parsefunc)(const char *, size_t, void *);
258494a2 192+
193+This type definition refers to the function pointer, which is used
194+to pass plugin functions into the core parsing subroutine. This definition
9e0529f5 195+is included to simplify the declaration of the parse_core() function.
258494a2 196+
197+
198+
199+
200+
201+ *-----------------------
202+ 4 New functions
203+ *-----------------------
204+
205+This section describes added functions.
206+
9e0529f5 207+4.1 get_variable
258494a2 208+
209+NAME
210+
9e0529f5 211+ get_variable
258494a2 212+
213+SYNOPSIS
9e0529f5 214+
215+ static const struct var_data *get_variable (const char *begin,
216+ size_t len,
217+ struct var_data *vdt);
258494a2 218+
219+DESCRIPTION
220+
9e0529f5 221+ This function searches an array pointed by vdt and tries to find
222+ the substitution variable, which name is identified with begin
223+ pointer and length of len bytes long.
258494a2 224+
9e0529f5 225+ This function is also responsible for updating length cache field
226+ of vdt elements and validating requested variables.
258494a2 227+
9e0529f5 228+ This function repports errors by sending human readable
229+ messages to the standard error stream.
258494a2 230+
258494a2 231+RETURN VALUE
232+
9e0529f5 233+ This function returns a pointer to the array element which is
234+ structure of var_data type, which contains variable definition
235+ of a given name. It returns NULL on error or failure.
258494a2 236+
258494a2 237+
9e0529f5 238+4.2 parse_core
258494a2 239+
240+NAME
241+
9e0529f5 242+ parse_core
258494a2 243+
244+SYNOPSIS
9e0529f5 245+ static int parse_core (const char *source, struct var_data *vdt,
246+ parsefunc outfn, void *result);
258494a2 247+
248+DESCRIPTION
249+
9e0529f5 250+ This is the parsing routine for query strings containing the
251+ substitution variables. It reads the string pointed with source
252+ and tries to catch a valid substitution variables or parts which
253+ are plain text blocks. The main purpose of using this function
254+ it to split source string into parts and for each part call
255+ outfn() function. Those parts are substrings identified by
256+ pointer to some element of the source string and size.
257+ Those elements are the result of splitting source string into
258+ logical parts: plain text substrings and substitution variables'
259+ values. To get the values of any found substitution variables
260+ parse_core() uses get_variable() function. To find places
261+ where substitution variables occurs it uses strstr() function
262+ in conjunction with SV_BEGIN_MARK and SV_END_MARK definitions.
263+ It passes vdt structure pointer to get_variable() function is
264+ it calls it.
265+
266+ outfn() function should be passed by its pointer which
267+ refers to declaration:
258494a2 268+
9e0529f5 269+ int (*outfn) (const char *begin,
270+ size_t string_length,
271+ void *void_pointer);
272+
273+ Each time outfn() is called the result argument of parse_core()
274+ is passed to the outfn() as a last argument (void_pointer).
275+
276+ Example:
277+
278+ Example string "$(local_part) AND $(domain)" will cause the
279+ outfn() to be called 3 times. First time for a value of
280+ $(local_part) substitution variable, second time
281+ for " AND " string, and the last time for $(domain) variable's
282+ value. Variables are passed to outfn() by their (found) values,
283+ plain text blocks are passed as they appear.
258494a2 284+
9e0529f5 285+ This function repports errors by sending human readable
286+ messages to the standard error stream.
258494a2 287+
288+RETURN VALUE
289+
9e0529f5 290+ This function returns -1 if an error has occured and 0 if
291+ everything went good.
292+
293+4.3 ParsePlugin_counter
258494a2 294+
295+NAME
296+
9e0529f5 297+ ParsePlugin_counter
258494a2 298+
299+SYNOPSIS
300+
9e0529f5 301+ int ParsePlugin_counter (const char *begin, size_t len,
302+ void *vp);
258494a2 303+
304+DESCRIPTION
305+
9e0529f5 306+ This is parsing plugin function. It simply increments the value
307+ found in the memory area pointed by vp. It assumes that
308+ the memory area is allocated for the variable of size_t
309+ type and that area was passed by (size_t *) pointer.
310+ The value is incremented by len argument. Begin argument
311+ is not used.
258494a2 312+
9e0529f5 313+ This function repports errors by sending human readable
314+ messages to the standard error stream.
258494a2 315+
316+RETURN VALUE
317+
9e0529f5 318+ This function returns the variable size or -1 if an error
319+ has occured, 0 if everything went good.
258494a2 320+
9e0529f5 321+4.4 ParsePlugin_builder
258494a2 322+
323+NAME
324+
9e0529f5 325+ ParsePlugin_builder
258494a2 326+
327+SYNOPSIS
328+
9e0529f5 329+ int ParsePlugin_builder (const char *begin, size_t len,
330+ void *vp);
258494a2 331+
332+DESCRIPTION
333+
9e0529f5 334+ This is parsing plugin function. It simply copies len bytes
335+ of a string pointed by begin to the end of memory area pointed by
336+ vp. It assumes that the area pointed by vp is passed by (char **)
337+ type pointer and refers to the (char *) pointer variable.
338+ After each call it shifts the value of pointer variable (char *)
339+ incrementing it by len bytes. Be careful when using this function
340+ - its changes the given pointer value. Always operate on an
341+ additional pointer type variable when passing it as the third
342+ argument.
258494a2 343+
344+RETURN VALUE
345+
9e0529f5 346+ This function returns the variable size or -1 if an error
347+ has occured, 0 if everything went good.
258494a2 348+
9e0529f5 349+4.5 parse_string
258494a2 350+
351+NAME
352+ parse_string
353+
354+SYNOPSIS
355+
9e0529f5 356+ static char *parse_string (const char *source, struct var_data *vdt);
258494a2 357+
358+DESCRIPTION
359+
360+ This function parses the string pointed with source according to the
361+ replacement instructions set in var_data array, which is passed with
9e0529f5 362+ its pointer vdt. It produces changed string located in newly allocated
258494a2 363+ memory area.
364+
9e0529f5 365+ This function calls parse_core() function with various parsing
366+ subroutines passed as function pointers.
258494a2 367+
9e0529f5 368+ 1. It uses parse_core() with ParsePlugin_counter to obtain the
369+ total amount of memory needed for the output string.
258494a2 370+
9e0529f5 371+ 2. It allocates the memory.
258494a2 372+
9e0529f5 373+ 3. It uses parse_core() with ParsePlugin_builder to build the
374+ output string.
375+
376+ This function repports errors by sending human readable
377+ messages to the standard error stream.
258494a2 378+
379+RETURN VALUE
380+
381+ Function returns pointer to the result buffer or NULL
382+ if an error has occured.
383+
384+WARNINGS
385+
386+ This function allocates some amount of memory using standard
387+ ANSI C routines. Memory allocated by this function should be
388+ freed with free().
389+
390+
9e0529f5 391+4.6 validate_password
258494a2 392+
393+NAME
394+ validate_password
395+
396+SYNOPSIS
397+
398+ static const char *validate_password (const char *password);
399+
400+DESCRIPTION
401+
402+ This function checks whether password string does contain
403+ any dangerous characters, which may be used to pass command
404+ strings to the database connection stream. If it founds one
405+ it replaces it by the backslash character.
406+
407+RETURN VALUE
408+
409+ It returns a pointer to the static buffer which contains
410+ validated password string or NULL if an error has occured.
411+
412+
9e0529f5 413+4.7 get_localpart
258494a2 414+
415+NAME
416+
417+ get_localpart
418+
419+SYNOPSIS
420+
421+ static const char *get_localpart (const char *username);
422+
423+DESCRIPTION
424+
425+ This function detaches local part of an e-mail address
426+ from string pointed with username and puts it to the
427+ buffer of the fixed length. All necessary cleaning is
428+ made on the result string.
429+
430+RETURN VALUE
431+
432+ Pointer to the static buffer containing local part or
433+ NULL if there was some error.
434+
435+
9e0529f5 436+4.8 get_domain
258494a2 437+
438+NAME
439+
440+ get_domain
441+
442+SYNOPSIS
443+
444+ static const char *get_domain (const char *username,
445+ const char *defdomain);
446+
447+DESCRIPTION
448+
449+ This function detaches domain part of an e-mail address
450+ from string pointed with username and puts it to the
451+ buffer of the fixed length. All necessary cleaning is
452+ made on the result string. If function cannot find domain
453+ part in the string the string pointed by defdomain is
454+ used instead.
455+
456+RETURN VALUE
457+
458+ Pointer to the static buffer containing domain name or
459+ NULL if there was some error.
460+
461+
9e0529f5 462+4.9 parse_select_clause
258494a2 463+
464+NAME
465+
466+ parse_select_clause
467+
468+SYNOPSIS
469+
470+ static char *parse_select_clause (const char *clause,
471+ const char *username,
472+ const char *defdomain);
473+
474+DESCRIPTION
475+
476+ This function is a simple wrapper to the parse_string()
477+ function. It parses a query pointed by caluse. username
478+ and defdomain strings are used to replace corresponding
479+ substitution strings if present in the query: $(local_part)
480+ and $(domain).
481+
482+
483+RETURN VALUE
484+
485+ Same as parse_string().
486+
487+
9e0529f5 488+4.10 parse_chpass_clause
258494a2 489+
490+NAME
491+
492+ parse_chpass_clause
493+
494+SYNOPSIS
495+
496+ static char *parse_chpass_clause (const char *clause,
497+ const char *username,
498+ const char *defdomain,
499+ const char *newpass,
500+ const char *newpass_crypt);
501+
502+DESCRIPTION
503+
504+ This function is a simple wrapper to the parse_string()
505+ function. It parses a query pointed by caluse. username,
506+ defdomain, newpass and newpass_crypt strings are used to
507+ replace corresponding substitution strings if present in
508+ the query: $(local_part), $(domain), $(newpass),
509+ $(newpass_crypt).
510+
511+RETURN VALUE
512+
513+ Same as parse_string().
514+
515+
516+
517+
518+
519+ *------------------------
520+ 5 Ideas and TODO
9e0529f5 521+ *------------------------
258494a2 522+
523+- solve problem with fixed buffer length of local part and the domain part
524+ strings after split (problem?)
525+- allow admin to set a group name instead of numerical group id
526+- allow admin to set a username instead of numerical user id
527+
528+- add clauses:
529+
530+ - MYSQL_PRESELECT_CLAUSE (query which comes before MYSQL_SELECT_CLAUSE)
531+ - MYSQL_POSTSELECT_CLAUSE (query which comes after MYSQL_SELECT_CLAUSE)
9e0529f5 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.
258494a2 545+
546+---------------------------------------------------------------------------
547+
548diff -Nur courier-imap-1.3.12.orig/authlib/authmysqllib.c courier-imap-1.3.12/authlib/authmysqllib.c
0fe2d1c5 549--- courier-imap-1.3.12.orig/authlib/authmysqllib.c Mon Aug 6 05:12:39 2001
9e0529f5 550+++ courier-imap-1.3.12/authlib/authmysqllib.c Sun Dec 30 01:41:00 2001
0b0a7302 551@@ -3,7 +3,6 @@
552 ** distribution information.
553 */
554
555-
556 #include <stdio.h>
557 #include <stdlib.h>
558 #include <string.h>
9e0529f5 559@@ -18,8 +17,26 @@
258494a2 560 #include "authmysqlrc.h"
561 #include "auth.h"
0fe2d1c5 562
258494a2 563+/* siefca@pld.org.pl */
9e0529f5 564+#define MAX_SUBSTITUTION_LEN 32
565+#define SV_BEGIN_MARK "$("
566+#define SV_END_MARK ")"
567+#define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
568+#define SV_END_LEN ((sizeof(SV_END_MARK))-1)
258494a2 569+
0fe2d1c5 570 static const char rcsid[]="$Id$";
571
9e0529f5 572+/* siefca@pld.org.pl */
0b0a7302 573+struct var_data {
0fe2d1c5 574+ const char *name;
575+ const char *value;
576+ const size_t size;
0b0a7302 577+ size_t value_length;
9e0529f5 578+ } ;
0b0a7302 579+
9e0529f5 580+/* siefca@pld.org.pl */
581+typedef int (*parsefunc)(const char *, size_t, void *);
0fe2d1c5 582+
583 static const char *read_env(const char *env)
584 {
585 static char *mysqlauth=0;
9e0529f5 586@@ -51,7 +68,13 @@
0fe2d1c5 587
588 for (i=0; i<mysqlauth_size; i++)
589 if (mysqlauth[i] == '\n')
590- mysqlauth[i]=0;
591+ { /* siefca@pld.org.pl */
0b0a7302 592+ if (!i || mysqlauth[i-1] != '\\')
593+ mysqlauth[i] ='\0';
0fe2d1c5 594+ else
0b0a7302 595+ mysqlauth[i] =
596+ mysqlauth[i-1] = ' ';
0fe2d1c5 597+ }
598 fclose(f);
599 }
600
9e0529f5 601@@ -199,17 +222,370 @@
0fe2d1c5 602 strcat(strcpy(p, "@"), defdomain);
603 }
604
605+/* siefca@pld.org.pl */
9e0529f5 606+static struct var_data *get_variable (const char *begin, size_t len,
607+ struct var_data *vdt)
0fe2d1c5 608+{
0b0a7302 609+struct var_data *vdp;
0fe2d1c5 610+
9e0529f5 611+ if (!begin || !vdt) /* should never happend */
612+ {
613+ fprintf (stderr, "authmysql: critical error while "
614+ "parsing substitution variable\n");
615+ return NULL;
616+ }
617+ if (len < 1)
618+ {
619+ fprintf (stderr, "authmysql: unknown empty substitution "
620+ "variable - aborting\n");
621+ return NULL;
622+ }
623+ if (len > MAX_SUBSTITUTION_LEN)
624+ {
625+ fprintf (stderr, "authmysql: variable name too long "
626+ "while parsing substitution\n"
627+ "authmysql: name begins with "
628+ SV_BEGIN_MARK
629+ "%.*s...\n", MAX_SUBSTITUTION_LEN, begin);
630+ return NULL;
631+ }
632+
633+ for (vdp=vdt; vdp->name; vdp++)
0b0a7302 634+ if (vdp->size == len+1 &&
635+ !strncmp(begin, vdp->name, len))
9e0529f5 636+ {
637+ if (!vdp->value)
638+ vdp->value = "";
639+ if (!vdp->value_length) /* length cache */
640+ vdp->value_length = strlen (vdp->value);
641+ return vdp;
642+ }
0b0a7302 643+
644+ fprintf (stderr, "authmysql: unknown substitution variable "
258494a2 645+ SV_BEGIN_MARK
646+ "%.*s"
647+ SV_END_MARK
648+ "\n", len, begin);
0b0a7302 649+
650+ return NULL;
651+}
0fe2d1c5 652+
0b0a7302 653+/* siefca@pld.org.pl */
9e0529f5 654+static int ParsePlugin_counter (const char *p, size_t length, void *vp)
655+{
656+ if (!p || !vp || length < 0)
657+ {
658+ fprintf (stderr, "authmysql: bad arguments while counting "
659+ "query string\n");
660+ return -1;
661+ }
662+
663+ *((size_t *)vp) += length;
664+
665+ return 0;
666+}
667+
668+/* siefca@pld.org.pl */
669+static int ParsePlugin_builder (const char *p, size_t length, void *vp)
0b0a7302 670+{
9e0529f5 671+char **strptr = (char **) vp;
672+
673+ if (!p || !vp || length < 0)
674+ {
675+ fprintf (stderr, "authmysql: bad arguments while building "
676+ "query string\n");
677+ return -1;
678+ }
679+
680+ if (!length) return 0;
681+ memcpy ((void *) *strptr, (void *) p, length);
682+ *strptr += length;
683+
684+ return 0;
685+}
686+
687+/* siefca@pld.org.pl */
688+static int parse_core (const char *source, struct var_data *vdt,
689+ parsefunc outfn, void *result)
690+{
691+int ret;
692+size_t v_size = 0,
258494a2 693+ t_size = 0;
0b0a7302 694+const char *p, *q, *e,
695+ *v_begin, *v_end,
9e0529f5 696+ *t_begin, *t_end;
697+struct var_data *v_ptr;
0b0a7302 698+
699+ if (!source)
700+ source = "";
9e0529f5 701+ if (!result)
702+ {
703+ fprintf (stderr, "authmysql: no memory allocated for result"
704+ "while parser core was invoked\n");
705+ return -1;
706+ }
707+ if (!vdt)
708+ {
709+ fprintf (stderr, "authmysql: no substitution table found "
710+ "while parser core was invoked\n");
711+ return -1;
712+ }
713+
0b0a7302 714+ q = source;
258494a2 715+ while ( (p=strstr(q, SV_BEGIN_MARK)) )
0fe2d1c5 716+ {
258494a2 717+ e = strstr (p, SV_END_MARK);
0b0a7302 718+ if (!e)
0fe2d1c5 719+ {
0b0a7302 720+ fprintf (stderr, "authmysql: syntax error in "
9e0529f5 721+ "substitution "
722+ "- no closing symbol fould!\n"
723+ "authmysql: bad variable begins with:"
724+ "%.*s...\n", MAX_SUBSTITUTION_LEN, p);
0b0a7302 725+ return -1;
0fe2d1c5 726+ }
0b0a7302 727+
728+ /*
729+ **
730+ ** __________sometext$(variable_name)_________
9e0529f5 731+ ** | | | |
0b0a7302 732+ ** t_begin' t_end' `v_begin `v_end
733+ **
734+ */
735+
9e0529f5 736+ v_begin = p+SV_BEGIN_LEN; /* variable field ptr */
737+ v_end = e-SV_END_LEN; /* variable field last character */
738+ v_size = v_end-v_begin+1;/* variable field length */
0b0a7302 739+
9e0529f5 740+ t_begin = q; /* text field ptr */
741+ t_end = p-1; /* text field last character */
742+ t_size = t_end-t_begin+1;/* text field length */
0b0a7302 743+
9e0529f5 744+ /* work on text */
745+ if ( (outfn (t_begin, t_size, result)) == -1 )
746+ return -1;
0b0a7302 747+
9e0529f5 748+ /* work on variable */
749+ v_ptr = get_variable (v_begin, v_size, vdt);
750+ if (!v_ptr) return -1;
751+
752+ if ( (outfn (v_ptr->value, v_ptr->value_length, result)) == -1 )
753+ return -1;
754+
755+ q = e + 1;
0b0a7302 756+ }
757+
9e0529f5 758+ /* work on last part of text if any */
759+ if (*q != '\0')
760+ if ( (outfn (q, strlen(q), result)) == -1 )
761+ return -1;
0fe2d1c5 762+
9e0529f5 763+ return 0;
0fe2d1c5 764+}
765+
766+/* siefca@pld.org.pl */
9e0529f5 767+static char *parse_string (const char *source, struct var_data *vdt)
0b0a7302 768+{
9e0529f5 769+char *output_buf = NULL,
770+ *pass_buf = NULL;
771+size_t buf_size = 2;
0b0a7302 772+
773+ if (source == NULL || *source == '\0' ||
9e0529f5 774+ vdt == NULL || vdt[0].name == NULL)
0b0a7302 775+ {
776+ fprintf (stderr, "authmysql: source clause is empty "
777+ "- this is critical error\n");
778+ return NULL;
779+ }
780+
9e0529f5 781+ /* phase 1 - count and validate string */
782+ if ( (parse_core (source, vdt, &ParsePlugin_counter, &buf_size)) != 0)
0b0a7302 783+ return NULL;
784+
9e0529f5 785+ /* phase 2 - allocate memory */
0b0a7302 786+ output_buf = malloc (buf_size);
787+ if (!output_buf)
788+ {
789+ perror ("malloc");
790+ return NULL;
791+ }
9e0529f5 792+ pass_buf = output_buf;
0b0a7302 793+
9e0529f5 794+ /* phase 3 - build the output string */
795+ if ( (parse_core (source, vdt, &ParsePlugin_builder, &pass_buf)) != 0)
0b0a7302 796+ {
797+ free (output_buf);
798+ return NULL;
9e0529f5 799+ }
800+ *pass_buf = '\0';
0b0a7302 801+
802+ return output_buf;
9e0529f5 803+}
0b0a7302 804+
805+/* siefca@pld.org.pl */
0fe2d1c5 806+static const char *get_localpart (const char *username)
807+{
258494a2 808+size_t lbuf = 0;
809+const char *l_end, *p;
810+char *q;
811+static char localpart_buf[130];
812+
813+ if (!username || *username == '\0') return NULL;
0fe2d1c5 814+
0fe2d1c5 815+ p = strchr(username,'@');
816+ if (p)
817+ {
258494a2 818+ if ((p-username) > 128)
819+ return NULL;
820+ l_end = p;
0fe2d1c5 821+ }
822+ else
823+ {
258494a2 824+ if ((lbuf = strlen(username)) > 128)
825+ return NULL;
826+ l_end = username + lbuf;
0fe2d1c5 827+ }
828+
258494a2 829+ p=username;
830+ q=localpart_buf;
831+
832+ while (*p && p != l_end)
0b0a7302 833+ if (*p == '\"' || *p == '\\' ||
834+ *p == '\'' || (int)(unsigned char)*p < ' ')
258494a2 835+ p++;
836+ else
837+ *q++ = *p++;
0b0a7302 838+
258494a2 839+ *q = '\0';
0fe2d1c5 840+ return localpart_buf;
841+}
842+
843+/* siefca@pld.org.pl */
844+static const char *get_domain (const char *username, const char *defdomain)
845+{
0b0a7302 846+static char domain_buf[260];
258494a2 847+const char *p;
848+char *q;
0fe2d1c5 849+
258494a2 850+ if (!username || *username == '\0') return NULL;
0fe2d1c5 851+ p = strchr(username,'@');
852+
258494a2 853+ if (!p || *(p+1) == '\0')
854+ {
855+ if (defdomain && *defdomain)
856+ return defdomain;
857+ else
858+ return NULL;
859+ }
860+
861+ p++;
862+ if ((strlen(p)) > 256)
863+ return NULL;
864+
865+ q = domain_buf;
866+ while (*p)
867+ if (*p == '\"' || *p == '\\' ||
868+ *p == '\'' || (int)(unsigned char)*p < ' ')
869+ p++;
870+ else
871+ *q++ = *p++;
872+
873+ *q = '\0';
874+ return domain_buf;
0fe2d1c5 875+}
876+
877+/* siefca@pld.org.pl */
0b0a7302 878+static const char *validate_password (const char *password)
879+{
880+static char pass_buf[260];
881+const char *p;
882+char *q;
883+
258494a2 884+ if (!password || *password == '\0' || (strlen(password)) > 256)
885+ return NULL;
0b0a7302 886+
258494a2 887+ p = password;
888+ q = pass_buf;
889+
890+ while (*p)
0b0a7302 891+ if (*p == '\"' || *p == '\\' || *p == '\'')
892+ *q++ = '\\';
258494a2 893+ else
894+ *q++ = *p++;
0b0a7302 895+
896+ *q = '\0';
0b0a7302 897+ return pass_buf;
898+}
899+
900+
901+/* siefca@pld.org.pl */
0fe2d1c5 902+static char *parse_select_clause (const char *clause, const char *username,
903+ const char *defdomain)
904+{
905+static struct var_data vd[]={
0b0a7302 906+ {"local_part", NULL, sizeof("local_part"), 0},
907+ {"domain", NULL, sizeof("domain"), 0},
908+ {NULL, NULL, 0, 0}};
0fe2d1c5 909+
910+ if (clause == NULL || *clause == '\0' ||
258494a2 911+ !username || *username == '\0')
912+ return NULL;
0fe2d1c5 913+
0b0a7302 914+ vd[0].value = get_localpart (username);
915+ vd[1].value = get_domain (username, defdomain);
258494a2 916+ if (!vd[0].value || !vd[1].value)
917+ return NULL;
0fe2d1c5 918+
0b0a7302 919+ return (parse_string (clause, vd));
0fe2d1c5 920+}
921+
922+/* siefca@pld.org.pl */
923+static char *parse_chpass_clause (const char *clause, const char *username,
924+ const char *defdomain, const char *newpass,
925+ const char *newpass_crypt)
926+{
927+static struct var_data vd[]={
0b0a7302 928+ {"local_part", NULL, sizeof("local_part"), 0},
929+ {"domain", NULL, sizeof("domain"), 0},
930+ {"newpass", NULL, sizeof("newpass"), 0},
931+ {"newpass_crypt", NULL, sizeof("newpass_crypt"), 0},
932+ {NULL, NULL, 0, 0}};
0fe2d1c5 933+
934+ if (clause == NULL || *clause == '\0' ||
935+ !username || *username == '\0' ||
936+ !newpass || *newpass == '\0' ||
258494a2 937+ !newpass_crypt || *newpass_crypt == '\0') return NULL;
0fe2d1c5 938+
0b0a7302 939+ vd[0].value = get_localpart (username);
940+ vd[1].value = get_domain (username, defdomain);
941+ vd[2].value = validate_password (newpass);
942+ vd[3].value = validate_password (newpass_crypt);
943+
944+ if (!vd[0].value || !vd[1].value ||
945+ !vd[2].value || !vd[3].value) return NULL;
0fe2d1c5 946+
0b0a7302 947+ return (parse_string (clause, vd));
0fe2d1c5 948+}
0fe2d1c5 949+
950 struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username)
951 {
952-const char *user_table;
953-const char *defdomain;
954+const char *user_table =NULL;
955+const char *defdomain =NULL;
956 char *querybuf, *p;
957 MYSQL_ROW row;
958 MYSQL_RES *result;
959
960-const char *crypt_field, *clear_field, *maildir_field, *home_field,
961- *name_field,
962- *login_field, *uid_field, *gid_field, *quota_field, *where_clause;
963+const char *crypt_field =NULL,
964+ *clear_field =NULL,
965+ *maildir_field =NULL,
966+ *home_field =NULL,
967+ *name_field =NULL,
968+ *login_field =NULL,
969+ *uid_field =NULL,
970+ *gid_field =NULL,
971+ *quota_field =NULL,
972+ *where_clause =NULL,
973+ *select_clause =NULL; /* siefca@pld.org.pl */
974
975 static const char query[]=
976 "SELECT %s, %s, %s, %s, %s, %s, %s, %s, %s FROM %s WHERE %s = \"";
9e0529f5 977@@ -232,79 +608,95 @@
0fe2d1c5 978 free(ui.fullname);
979 memset(&ui, 0, sizeof(ui));
980
981- user_table=read_env("MYSQL_USER_TABLE");
982- defdomain=read_env("DEFAULT_DOMAIN");
983-
984- if (!user_table)
985+ select_clause=read_env("MYSQL_SELECT_CLAUSE");
986+ defdomain=read_env("DEFAULT_DOMAIN");
987+
988+ if (!select_clause) /* siefca@pld.org.pl */
989 {
990- fprintf(stderr, "authmysql: MYSQL_USER_TABLE not set in "
991- AUTHMYSQLRC ".\n");
992- return (0);
993- }
994+ user_table=read_env("MYSQL_USER_TABLE");
995
996- crypt_field=read_env("MYSQL_CRYPT_PWFIELD");
997- clear_field=read_env("MYSQL_CLEAR_PWFIELD");
998- name_field=read_env("MYSQL_NAME_FIELD");
999+ if (!user_table)
1000+ {
1001+ fprintf(stderr, "authmysql: MYSQL_USER_TABLE not set in "
1002+ AUTHMYSQLRC ".\n");
1003+ return (0);
1004+ }
1005
1006- if (!crypt_field && !clear_field)
1007- {
1008- fprintf(stderr,
1009- "authmysql: MYSQL_CRYPT_PWFIELD and "
1010- "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC ".\n");
1011- return (0);
1012- }
1013- if (!crypt_field) crypt_field="\"\"";
1014- if (!clear_field) clear_field="\"\"";
1015- if (!name_field) name_field="\"\"";
1016+ crypt_field=read_env("MYSQL_CRYPT_PWFIELD");
1017+ clear_field=read_env("MYSQL_CLEAR_PWFIELD");
1018+ name_field=read_env("MYSQL_NAME_FIELD");
258494a2 1019+
0fe2d1c5 1020+ if (!crypt_field && !clear_field)
1021+ {
1022+ fprintf(stderr,
1023+ "authmysql: MYSQL_CRYPT_PWFIELD and "
1024+ "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC ".\n");
1025+ return (0);
1026+ }
1027+ if (!crypt_field) crypt_field="\"\"";
1028+ if (!clear_field) clear_field="\"\"";
1029+ if (!name_field) name_field="\"\"";
0fe2d1c5 1030
258494a2 1031- uid_field = read_env("MYSQL_UID_FIELD");
1032- if (!uid_field) uid_field = "uid";
0b0a7302 1033+ uid_field = read_env("MYSQL_UID_FIELD");
1034+ if (!uid_field) uid_field = "uid";
0fe2d1c5 1035
258494a2 1036- gid_field = read_env("MYSQL_GID_FIELD");
1037- if (!gid_field) gid_field = "gid";
0b0a7302 1038+ gid_field = read_env("MYSQL_GID_FIELD");
1039+ if (!gid_field) gid_field = "gid";
0fe2d1c5 1040
258494a2 1041- login_field = read_env("MYSQL_LOGIN_FIELD");
1042- if (!login_field) login_field = "id";
0b0a7302 1043+ login_field = read_env("MYSQL_LOGIN_FIELD");
1044+ if (!login_field) login_field = "id";
0fe2d1c5 1045
258494a2 1046- home_field = read_env("MYSQL_HOME_FIELD");
1047- if (!home_field) home_field = "home";
0b0a7302 1048+ home_field = read_env("MYSQL_HOME_FIELD");
1049+ if (!home_field) home_field = "home";
0fe2d1c5 1050
258494a2 1051- maildir_field=read_env("MYSQL_MAILDIR_FIELD");
1052- if (!maildir_field) maildir_field="\"\"";
0b0a7302 1053+ maildir_field=read_env("MYSQL_MAILDIR_FIELD");
1054+ if (!maildir_field) maildir_field="\"\"";
0fe2d1c5 1055
258494a2 1056- quota_field=read_env("MYSQL_QUOTA_FIELD");
1057- if (!quota_field) quota_field="\"\"";
0b0a7302 1058+ quota_field=read_env("MYSQL_QUOTA_FIELD");
1059+ if (!quota_field) quota_field="\"\"";
258494a2 1060
1061- where_clause=read_env("MYSQL_WHERE_CLAUSE");
1062- if (!where_clause) where_clause = "";
0fe2d1c5 1063+ where_clause=read_env("MYSQL_WHERE_CLAUSE");
1064+ if (!where_clause) where_clause = "";
1065+ }
1066
1067 if (!defdomain) defdomain="";
1068
1069- querybuf=malloc(sizeof(query) + 100 + strlen(user_table) + strlen(defdomain)
1070- + strlen(crypt_field) + strlen(clear_field) + strlen(maildir_field)
1071- + strlen(uid_field) + strlen(gid_field) + 2 * strlen(login_field)
1072- + strlen(home_field) + strlen(quota_field) + strlen(where_clause)
0b0a7302 1073- + strlen(name_field));
1074- if (!querybuf)
0fe2d1c5 1075+ if (!select_clause) /* siefca@pld.org.pl */
0b0a7302 1076 {
1077- perror("malloc");
1078- return (0);
1079- }
0fe2d1c5 1080+ querybuf=malloc(sizeof(query) + 100 + strlen(user_table) + strlen(defdomain)
1081+ + strlen(crypt_field) + strlen(clear_field) + strlen(maildir_field)
1082+ + strlen(uid_field) + strlen(gid_field) + 2 * strlen(login_field)
1083+ + strlen(home_field) + strlen(quota_field) + strlen(where_clause)
0b0a7302 1084+ + strlen(name_field));
258494a2 1085+
0fe2d1c5 1086+ if (!querybuf)
1087+ {
1088+ perror("malloc");
1089+ return (0);
1090+ }
9e0529f5 1091+
1092+ sprintf(querybuf, query, login_field, crypt_field, clear_field,
1093+ uid_field, gid_field, home_field, maildir_field, quota_field,
1094+ name_field, user_table, login_field);
258494a2 1095
1096- sprintf(querybuf, query, login_field, crypt_field, clear_field,
1097- uid_field, gid_field, home_field, maildir_field, quota_field,
1098- name_field, user_table, login_field);
1099- p=querybuf+strlen(querybuf);
9e0529f5 1100+ p=querybuf+strlen(querybuf);
0b0a7302 1101
1102- append_username(p, username, defdomain);
1103- strcat(p, "\"");
0fe2d1c5 1104+ append_username(p, username, defdomain);
1105+ strcat(p, "\"");
0b0a7302 1106
1107- if (strcmp(where_clause, "")) {
1108- strcat(p, " AND (");
1109- strcat(p, where_clause);
1110- strcat(p, ")");
0fe2d1c5 1111+ if (strcmp(where_clause, "")) {
1112+ strcat(p, " AND (");
1113+ strcat(p, where_clause);
1114+ strcat(p, ")");
1115+ }
0b0a7302 1116 }
1117-
0fe2d1c5 1118+ else
0b0a7302 1119+ {
0fe2d1c5 1120+ /* siefca@pld.org.pl */
1121+ querybuf=parse_select_clause (select_clause, username, defdomain);
1122+ if (!querybuf) return 0;
0b0a7302 1123+ }
1124+
0fe2d1c5 1125 if (mysql_query (mysql, querybuf))
1126 {
1127 /* <o.blasnik@nextra.de> */
9e0529f5 1128@@ -379,12 +771,13 @@
0fe2d1c5 1129 const char *comma;
1130 int rc=0;
1131
1132- const char *clear_field;
1133- const char *crypt_field;
1134- const char *defdomain;
1135- const char *where_clause;
1136- const char *user_table;
1137- const char *login_field;
1138+ const char *clear_field =NULL,
1139+ *crypt_field =NULL,
1140+ *defdomain =NULL,
1141+ *where_clause =NULL,
1142+ *user_table =NULL,
1143+ *login_field =NULL,
1144+ *chpass_clause =NULL; /* siefca@pld.org.pl */
1145
1146 if (!mysql)
1147 return (-1);
9e0529f5 1148@@ -412,21 +805,34 @@
0fe2d1c5 1149 ++l;
1150 }
1151
1152- login_field = read_env("MYSQL_LOGIN_FIELD");
1153- if (!login_field) login_field = "id";
1154- crypt_field=read_env("MYSQL_CRYPT_PWFIELD");
1155- clear_field=read_env("MYSQL_CLEAR_PWFIELD");
1156+ /* siefca@pld.org.pl */
1157+ chpass_clause=read_env("MYSQL_CHPASS_CLAUSE");
1158 defdomain=read_env("DEFAULT_DOMAIN");
1159- where_clause=read_env("MYSQL_WHERE_CLAUSE");
1160 user_table=read_env("MYSQL_USER_TABLE");
1161-
1162- sql_buf=malloc(strlen(crypt_field ? crypt_field:"")
1163- + strlen(clear_field ? clear_field:"")
1164- + strlen(defdomain ? defdomain:"")
1165- + strlen(login_field) + l + strlen(newpass_crypt)
1166- + strlen(user_table)
1167- + strlen(where_clause ? where_clause:"")
1168- + 200);
1169+ if (!chpass_clause)
1170+ {
1171+ login_field = read_env("MYSQL_LOGIN_FIELD");
1172+ if (!login_field) login_field = "id";
1173+ crypt_field=read_env("MYSQL_CRYPT_PWFIELD");
1174+ clear_field=read_env("MYSQL_CLEAR_PWFIELD");
1175+ where_clause=read_env("MYSQL_WHERE_CLAUSE");
1176+ sql_buf=malloc(strlen(crypt_field ? crypt_field:"")
1177+ + strlen(clear_field ? clear_field:"")
1178+ + strlen(defdomain ? defdomain:"")
1179+ + strlen(login_field) + l + strlen(newpass_crypt)
1180+ + strlen(user_table)
1181+ + strlen(where_clause ? where_clause:"")
1182+ + 200);
1183+ }
1184+ else
1185+ {
1186+ sql_buf=parse_chpass_clause(chpass_clause,
1187+ user,
1188+ defdomain,
1189+ pass,
1190+ newpass_crypt);
1191+ }
1192+
1193
1194 if (!sql_buf)
1195 {
9e0529f5 1196@@ -434,53 +840,57 @@
0fe2d1c5 1197 return (-1);
1198 }
1199
1200- sprintf(sql_buf, "UPDATE %s SET", user_table);
1201-
1202- comma="";
1203-
1204- if (clear_field && *clear_field)
1205+ if (!chpass_clause) /*siefca@pld.org.pl */
1206 {
1207- char *q;
1208+ sprintf(sql_buf, "UPDATE %s SET", user_table);
1209
1210- strcat(strcat(strcat(sql_buf, " "), clear_field),
1211- "=\"");
1212+ comma="";
1213
1214- q=sql_buf+strlen(sql_buf);
1215- while (*pass)
1216+ if (clear_field && *clear_field)
1217 {
1218- if (*pass == '"' || *pass == '\\')
1219- *q++= '\\';
1220- *q++ = *pass++;
1221+ char *q;
1222+
1223+ strcat(strcat(strcat(sql_buf, " "), clear_field),
1224+ "=\"");
1225+
1226+ q=sql_buf+strlen(sql_buf);
1227+ while (*pass)
1228+ {
1229+ if (*pass == '"' || *pass == '\\')
1230+ *q++= '\\';
1231+ *q++ = *pass++;
1232+ }
1233+ strcpy(q, "\"");
1234+ comma=", ";
1235 }
1236- strcpy(q, "\"");
1237- comma=", ";
1238- }
1239
1240- if (crypt_field && *crypt_field)
1241- {
1242- strcat(strcat(strcat(strcat(strcat(strcat(sql_buf, comma),
1243- " "),
1244- crypt_field),
1245- "=\""),
1246- newpass_crypt_ptr),
1247- "\"");
1248- }
1249- free(newpass_crypt);
1250+ if (crypt_field && *crypt_field)
1251+ {
1252+ strcat(strcat(strcat(strcat(strcat(strcat(sql_buf, comma),
1253+ " "),
1254+ crypt_field),
1255+ "=\""),
1256+ newpass_crypt_ptr),
1257+ "\"");
1258+ }
1259+ free(newpass_crypt);
1260
1261- strcat(strcat(strcat(sql_buf, " WHERE "),
1262- login_field),
1263- "=\"");
1264+ strcat(strcat(strcat(sql_buf, " WHERE "),
1265+ login_field),
1266+ "=\"");
1267
1268- append_username(sql_buf+strlen(sql_buf), user, defdomain);
1269+ append_username(sql_buf+strlen(sql_buf), user, defdomain);
1270
1271- strcat(sql_buf, "\"");
1272+ strcat(sql_buf, "\"");
1273
1274- if (where_clause && *where_clause)
1275- {
1276- strcat(sql_buf, " AND (");
1277- strcat(sql_buf, where_clause);
1278- strcat(sql_buf, ")");
1279- }
1280+ if (where_clause && *where_clause)
1281+ {
1282+ strcat(sql_buf, " AND (");
1283+ strcat(sql_buf, where_clause);
1284+ strcat(sql_buf, ")");
1285+ }
1286+
1287+ } /* end of: if (!chpass_clause) */
1288
1289 if (mysql_query (mysql, sql_buf))
1290 {
258494a2 1291diff -Nur courier-imap-1.3.12.orig/authlib/authmysqlrc courier-imap-1.3.12/authlib/authmysqlrc
0fe2d1c5 1292--- courier-imap-1.3.12.orig/authlib/authmysqlrc Sun Oct 7 18:32:56 2001
9e0529f5 1293+++ courier-imap-1.3.12/authlib/authmysqlrc Fri Dec 28 02:08:01 2001
0b0a7302 1294@@ -141,4 +141,65 @@
0fe2d1c5 1295 #
1296 # MYSQL_WHERE_CLAUSE server='mailhost.example.com'
1297
1298-
1299+##NAME: MYSQL_SELECT_CLAUSE:0
1300+#
1301+# (EXPERIMENTAL)
1302+# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database,
1303+# which is structuraly different from proposed. The fixed string will
1304+# be used to do a SELECT operation on database, which should return fields
0b0a7302 1305+# in order specified bellow:
0fe2d1c5 1306+#
1307+# username, cryptpw, uid, gid, clearpw, home, maildir, quota, fullname
1308+#
1309+# Enabling this option causes ignorance of any other field-related
1310+# options, excluding default domain.
1311+#
1312+# There are two variables, which you can use. Substitution will be made
1313+# for them, so you can put entered username (local part) and domain name
0b0a7302 1314+# in the right place of your query. These variables are:
1315+# $(local_part) and $(domain)
0fe2d1c5 1316+#
1317+# If a $(domain) is empty (not given by the remote user) the default domain
1318+# name is used in its place.
1319+#
1320+# This example is a little bit modified adaptation of vmail-sql
1321+# database scheme:
0b0a7302 1322+#
1323+# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \
0fe2d1c5 1324+# CONCAT('{MD5}', popbox.password_hash), \
1325+# domain.uid, \
1326+# domain.gid, \
1327+# popbox.clearpw, \
1328+# CONCAT(domain.path, '/', popbox.mbox_name), \
1329+# '', \
1330+# domain.quota, \
1331+# '', \
1332+# FROM popbox, domain \
1333+# WHERE popbox.local_part = '$(local_part)' \
1334+# AND popbox.domain_name = '$(domain)' \
1335+# AND popbox.domain_name = domain.domain_name
1336+#
1337+##NAME: MYSQL_CHPASS_CLAUSE:0
1338+#
1339+# (EXPERIMENTAL)
1340+# This is optional, MYSQL_CHPASS_CLAUSE can be set when you have a database,
1341+# which is structuraly different from proposed. The fixed string will
1342+# be used to do an UPDATE operation on database. In other words, it is
1343+# used, when changing password.
1344+#
1345+# There are four variables, which you can use. Substitution will be made
1346+# for them, so you can put entered username (local part) and domain name
1347+# in the right place of your query. There variables are:
1348+# $(local_part) , $(domain) , $(newpass) , $(newpass_crypt)
1349+#
1350+# If a $(domain) is empty (not given by the remote user) the default domain
1351+# name is used in its place.
1352+# $(newpass) contains plain password
1353+# $(newpass_crypt) contains its crypted form
1354+#
1355+# MYSQL_CHPASS_CLAUSE UPDATE popbox \
1356+# SET clearpw='$(newpass)', \
1357+# password_hash='$(newpass_crypt)' \
1358+# WHERE local_part='$(local_part)' \
1359+# AND domain_name='$(domain)'
1360+#
This page took 0.279063 seconds and 4 git commands to generate.