]> git.pld-linux.org Git - packages/courier-imap.git/blob - courier-imap-myownquery.patch
- myownquery.patch simplified according to suggestions from Sam Varshavchik
[packages/courier-imap.git] / courier-imap-myownquery.patch
1 diff -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
3 +++ courier-imap-1.3.12/authlib/README.myownquery       Sun Dec 30 01:41:38 2001
4 @@ -0,0 +1,543 @@
5 +
6 +
7 +
8 +
9 +           Developer Notes for courier-imap-myownquery.patch
10 +
11 +
12 +
13 +
14 +                                                       document version: 1.03
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
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
53 +  
54 +5 Ideas and TODO
55 +
56 +6 Thanks
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 +
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)
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 ")".
134 +MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's
135 +identifier (name).
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 +
177 +struct var_data vdt[] =        {
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 +
191 +typedef int (*parsefunc)(const char *, size_t, void *);
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
195 +is included to simplify the declaration of the parse_core() function.
196 +
197 +
198 +
199 +
200 +
201 +                   *-----------------------
202 +                    4 New functions
203 +                   *-----------------------
204 +
205 +This section describes added functions.
206 +
207 +4.1 get_variable
208 +
209 +NAME
210 +
211 +       get_variable
212 +
213 +SYNOPSIS
214 +
215 +       static const struct var_data *get_variable (const char *begin,
216 +                                                   size_t len,
217 +                                                   struct var_data *vdt);
218 +
219 +DESCRIPTION
220 +
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.
224 +       
225 +       This function is also responsible for updating length cache field
226 +       of vdt elements and validating requested variables.
227 +       
228 +       This function repports errors by sending human readable
229 +       messages to the standard error stream.
230 +
231 +RETURN VALUE
232 +
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.
236 +
237 +
238 +4.2 parse_core
239 +
240 +NAME
241 +
242 +       parse_core
243 +
244 +SYNOPSIS
245 +       static int    parse_core (const char *source, struct var_data *vdt,
246 +                                 parsefunc outfn, void *result);
247 +
248 +DESCRIPTION
249 +
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:
268 +       
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.
284 +
285 +       This function repports errors by sending human readable
286 +       messages to the standard error stream.
287 +
288 +RETURN VALUE
289 +
290 +       This function returns -1 if an error has occured and 0 if
291 +       everything went good.
292 +       
293 +4.3 ParsePlugin_counter
294 +
295 +NAME
296 +
297 +       ParsePlugin_counter
298 +
299 +SYNOPSIS
300 +
301 +       int    ParsePlugin_counter (const char *begin, size_t len,
302 +                                   void *vp);
303 +
304 +DESCRIPTION
305 +
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.
312 +
313 +       This function repports errors by sending human readable
314 +       messages to the standard error stream.
315 +
316 +RETURN VALUE
317 +
318 +       This function returns the variable size or -1 if an error
319 +       has occured, 0 if everything went good.
320 +
321 +4.4 ParsePlugin_builder
322 +
323 +NAME
324 +
325 +       ParsePlugin_builder
326 +
327 +SYNOPSIS
328 +
329 +       int    ParsePlugin_builder (const char *begin, size_t len,
330 +                                   void *vp);
331 +
332 +DESCRIPTION
333 +
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.
343 +
344 +RETURN VALUE
345 +
346 +       This function returns the variable size or -1 if an error
347 +       has occured, 0 if everything went good.
348 +
349 +4.5 parse_string
350 +
351 +NAME
352 +       parse_string
353 +
354 +SYNOPSIS
355 +
356 +       static char *parse_string (const char *source, struct var_data *vdt);
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
362 +       its pointer vdt. It produces changed string located in newly allocated
363 +       memory area.
364 +
365 +       This function calls parse_core() function with various parsing
366 +       subroutines passed as function pointers.
367 +       
368 +       1. It uses parse_core() with ParsePlugin_counter to obtain the
369 +          total amount of memory needed for the output string.
370 +       
371 +       2. It allocates the memory.
372 +       
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.
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 +
391 +4.6 validate_password
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 +
413 +4.7 get_localpart
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 +
436 +4.8 get_domain
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 +
462 +4.9 parse_select_clause
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 +
488 +4.10 parse_chpass_clause
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
521 +                   *------------------------
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)
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 +---------------------------------------------------------------------------
547 +
548 diff -Nur courier-imap-1.3.12.orig/authlib/authmysqllib.c courier-imap-1.3.12/authlib/authmysqllib.c
549 --- courier-imap-1.3.12.orig/authlib/authmysqllib.c     Mon Aug  6 05:12:39 2001
550 +++ courier-imap-1.3.12/authlib/authmysqllib.c  Sun Dec 30 01:41:00 2001
551 @@ -3,7 +3,6 @@
552  ** distribution information.
553  */
554  
555 -
556  #include       <stdio.h>
557  #include       <stdlib.h>
558  #include       <string.h>
559 @@ -18,8 +17,26 @@
560  #include       "authmysqlrc.h"
561  #include       "auth.h"
562  
563 +/* siefca@pld.org.pl */
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)
569 +
570  static const char rcsid[]="$Id$";
571  
572 +/* siefca@pld.org.pl */
573 +struct var_data {                      
574 +       const char *name;
575 +       const char *value;
576 +       const size_t size;
577 +       size_t value_length;
578 +       } ;
579 +
580 +/* siefca@pld.org.pl */
581 +typedef int (*parsefunc)(const char *, size_t, void *);
582 +
583  static const char *read_env(const char *env)
584  {
585  static char *mysqlauth=0;
586 @@ -51,7 +68,13 @@
587  
588                 for (i=0; i<mysqlauth_size; i++)
589                         if (mysqlauth[i] == '\n')
590 -                               mysqlauth[i]=0;
591 +                       {       /* siefca@pld.org.pl */
592 +                               if (!i || mysqlauth[i-1] != '\\')
593 +                                       mysqlauth[i]    ='\0';
594 +                               else
595 +                                       mysqlauth[i]    =
596 +                                       mysqlauth[i-1]  = ' ';
597 +                       }
598                 fclose(f);
599         }
600  
601 @@ -199,17 +222,370 @@
602                 strcat(strcpy(p, "@"), defdomain);
603  }
604  
605 +/* siefca@pld.org.pl */
606 +static struct var_data *get_variable (const char *begin, size_t len,
607 +                                          struct var_data *vdt)
608 +{
609 +struct var_data *vdp;
610 +
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++)
634 +               if (vdp->size == len+1 &&
635 +                   !strncmp(begin, vdp->name, len))
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 +               }
643 +       
644 +       fprintf (stderr, "authmysql: unknown substitution variable "
645 +                        SV_BEGIN_MARK
646 +                        "%.*s"
647 +                        SV_END_MARK
648 +                        "\n", len, begin);
649 +       
650 +       return NULL;
651 +}
652 +
653 +/* siefca@pld.org.pl */
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)
670 +{
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,
693 +       t_size          = 0;
694 +const char     *p, *q, *e,
695 +               *v_begin, *v_end,
696 +               *t_begin, *t_end;
697 +struct var_data        *v_ptr;
698 +
699 +       if (!source)
700 +               source = "";
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 +       
714 +       q = source;
715 +       while ( (p=strstr(q, SV_BEGIN_MARK)) )
716 +       {
717 +               e = strstr (p, SV_END_MARK);
718 +               if (!e)
719 +               {
720 +                       fprintf (stderr, "authmysql: syntax error in "
721 +                                        "substitution "
722 +                                        "- no closing symbol fould!\n"
723 +                                        "authmysql: bad variable begins with:"
724 +                                        "%.*s...\n", MAX_SUBSTITUTION_LEN, p);
725 +                       return -1;
726 +               }
727 +               
728 +               /*
729 +                **
730 +                **          __________sometext$(variable_name)_________
731 +                **                    |      |  |           |  
732 +                **             t_begin' t_end'  `v_begin    `v_end
733 +                **
734 +                 */
735 +
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          */
739 +               
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              */
743 +
744 +               /* work on text */
745 +               if ( (outfn (t_begin, t_size, result)) == -1 )
746 +                       return -1;
747 +               
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;
756 +       }
757 +
758 +       /* work on last part of text if any */
759 +       if (*q != '\0')
760 +               if ( (outfn (q, strlen(q), result)) == -1 )
761 +                       return -1;
762 +
763 +       return 0;
764 +}
765 +
766 +/* siefca@pld.org.pl */
767 +static char *parse_string (const char *source, struct var_data *vdt)
768 +{
769 +char   *output_buf     = NULL,
770 +       *pass_buf       = NULL;
771 +size_t buf_size        = 2;
772 +
773 +       if (source == NULL || *source == '\0' || 
774 +           vdt == NULL    || vdt[0].name == NULL)
775 +       {
776 +               fprintf (stderr, "authmysql: source clause is empty "
777 +                                "- this is critical error\n");
778 +               return NULL;
779 +       }
780 +
781 +       /* phase 1 - count and validate string */
782 +       if ( (parse_core (source, vdt, &ParsePlugin_counter, &buf_size)) != 0)
783 +               return NULL;
784 +
785 +       /* phase 2 - allocate memory */
786 +       output_buf = malloc (buf_size);
787 +       if (!output_buf)
788 +       {
789 +               perror ("malloc");
790 +               return NULL;
791 +       }
792 +       pass_buf = output_buf;
793 +
794 +       /* phase 3 - build the output string */
795 +       if ( (parse_core (source, vdt, &ParsePlugin_builder, &pass_buf)) != 0)
796 +       {
797 +               free (output_buf);
798 +               return NULL;
799 +       }       
800 +       *pass_buf = '\0';
801 +       
802 +       return output_buf;
803 +}
804 +
805 +/* siefca@pld.org.pl */
806 +static const char *get_localpart (const char *username)
807 +{
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;
814 +       
815 +       p = strchr(username,'@');
816 +       if (p)
817 +       {
818 +               if ((p-username) > 128)
819 +                       return NULL;
820 +               l_end = p;
821 +       }
822 +       else
823 +       {
824 +               if ((lbuf = strlen(username)) > 128)
825 +                       return NULL;
826 +               l_end = username + lbuf;
827 +       }
828 +
829 +       p=username;
830 +       q=localpart_buf;
831 +       
832 +       while (*p && p != l_end)
833 +               if (*p == '\"' || *p == '\\' ||
834 +                   *p == '\'' || (int)(unsigned char)*p < ' ')
835 +                       p++;
836 +               else
837 +                       *q++ = *p++;
838 +
839 +       *q = '\0';
840 +       return localpart_buf;
841 +}
842 +
843 +/* siefca@pld.org.pl */
844 +static const char *get_domain (const char *username, const char *defdomain)
845 +{
846 +static char    domain_buf[260];
847 +const char     *p;
848 +char           *q;
849 +       
850 +       if (!username || *username == '\0')     return NULL;
851 +       p = strchr(username,'@');
852 +       
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;
875 +}
876 +
877 +/* siefca@pld.org.pl */
878 +static const char *validate_password (const char *password)
879 +{
880 +static char    pass_buf[260];
881 +const char     *p;
882 +char           *q;
883 +       
884 +       if (!password || *password == '\0' || (strlen(password)) > 256)
885 +               return NULL;
886 +       
887 +       p = password;
888 +       q = pass_buf;
889 +       
890 +       while (*p)
891 +               if (*p == '\"' || *p == '\\' || *p == '\'')
892 +                       *q++ = '\\';
893 +               else
894 +                       *q++ = *p++;    
895 +       
896 +       *q = '\0';
897 +       return pass_buf;
898 +}
899 +
900 +
901 +/* siefca@pld.org.pl */
902 +static char *parse_select_clause (const char *clause, const char *username,
903 +                                 const char *defdomain)
904 +{
905 +static struct var_data vd[]={
906 +           {"local_part",      NULL,   sizeof("local_part"),   0},
907 +           {"domain",          NULL,   sizeof("domain"),       0},
908 +           {NULL,              NULL,   0,                      0}};
909 +
910 +       if (clause == NULL || *clause == '\0' ||
911 +           !username || *username == '\0')
912 +               return NULL;
913 +       
914 +       vd[0].value     = get_localpart (username);
915 +       vd[1].value     = get_domain (username, defdomain);
916 +       if (!vd[0].value || !vd[1].value)
917 +               return NULL;
918 +       
919 +       return (parse_string (clause, vd));
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[]={
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}};
933 +
934 +       if (clause == NULL || *clause == '\0'           ||
935 +           !username || *username == '\0'              ||
936 +           !newpass || *newpass == '\0'                ||
937 +           !newpass_crypt || *newpass_crypt == '\0')   return NULL;
938 +
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;
946 +
947 +       return (parse_string (clause, vd));
948 +}
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 = \"";
977 @@ -232,79 +608,95 @@
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");
1019 +
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="\"\"";
1030  
1031 -       uid_field = read_env("MYSQL_UID_FIELD");
1032 -       if (!uid_field) uid_field = "uid";
1033 +               uid_field = read_env("MYSQL_UID_FIELD");
1034 +               if (!uid_field) uid_field = "uid";
1035  
1036 -       gid_field = read_env("MYSQL_GID_FIELD");
1037 -       if (!gid_field) gid_field = "gid";
1038 +               gid_field = read_env("MYSQL_GID_FIELD");
1039 +               if (!gid_field) gid_field = "gid";
1040  
1041 -       login_field = read_env("MYSQL_LOGIN_FIELD");
1042 -       if (!login_field) login_field = "id";
1043 +               login_field = read_env("MYSQL_LOGIN_FIELD");
1044 +               if (!login_field) login_field = "id";
1045  
1046 -       home_field = read_env("MYSQL_HOME_FIELD");
1047 -       if (!home_field) home_field = "home";
1048 +               home_field = read_env("MYSQL_HOME_FIELD");
1049 +               if (!home_field) home_field = "home";
1050  
1051 -       maildir_field=read_env("MYSQL_MAILDIR_FIELD");
1052 -       if (!maildir_field) maildir_field="\"\"";
1053 +               maildir_field=read_env("MYSQL_MAILDIR_FIELD");
1054 +               if (!maildir_field) maildir_field="\"\"";
1055  
1056 -       quota_field=read_env("MYSQL_QUOTA_FIELD");
1057 -       if (!quota_field) quota_field="\"\""; 
1058 +               quota_field=read_env("MYSQL_QUOTA_FIELD");
1059 +               if (!quota_field) quota_field="\"\""; 
1060  
1061 -       where_clause=read_env("MYSQL_WHERE_CLAUSE");
1062 -       if (!where_clause) where_clause = "";
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)
1073 -                       + strlen(name_field));
1074 -       if (!querybuf)
1075 +       if (!select_clause) /* siefca@pld.org.pl */
1076         {
1077 -               perror("malloc");
1078 -               return (0);
1079 -       }
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)
1084 +                       + strlen(name_field));
1085 +
1086 +               if (!querybuf)
1087 +               {
1088 +                       perror("malloc");
1089 +                       return (0);
1090 +               }
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);
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);
1100 +               p=querybuf+strlen(querybuf);
1101  
1102 -       append_username(p, username, defdomain);
1103 -       strcat(p, "\"");
1104 +               append_username(p, username, defdomain);
1105 +               strcat(p, "\"");
1106         
1107 -       if (strcmp(where_clause, "")) {
1108 -               strcat(p, " AND (");
1109 -               strcat(p, where_clause);
1110 -               strcat(p, ")");
1111 +               if (strcmp(where_clause, "")) {
1112 +                       strcat(p, " AND (");
1113 +                       strcat(p, where_clause);
1114 +                       strcat(p, ")");
1115 +               }
1116         }
1117 -       
1118 +       else
1119 +       {
1120 +               /* siefca@pld.org.pl */
1121 +               querybuf=parse_select_clause (select_clause, username, defdomain);
1122 +               if (!querybuf) return 0;
1123 +       }
1124 +
1125         if (mysql_query (mysql, querybuf))
1126         {
1127                 /* <o.blasnik@nextra.de> */
1128 @@ -379,12 +771,13 @@
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);
1148 @@ -412,21 +805,34 @@
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         {
1196 @@ -434,53 +840,57 @@
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         {
1291 diff -Nur courier-imap-1.3.12.orig/authlib/authmysqlrc courier-imap-1.3.12/authlib/authmysqlrc
1292 --- courier-imap-1.3.12.orig/authlib/authmysqlrc        Sun Oct  7 18:32:56 2001
1293 +++ courier-imap-1.3.12/authlib/authmysqlrc     Fri Dec 28 02:08:01 2001
1294 @@ -141,4 +141,65 @@
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
1305 +# in order specified bellow:
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
1314 +# in the right place of your query. These variables are:
1315 +#              $(local_part) and $(domain)
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:
1322 +#
1323 +# MYSQL_SELECT_CLAUSE  SELECT popbox.local_part,                       \
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.191241 seconds and 3 git commands to generate.