diff -Nur courier-imap-1.3.12.orig/authlib/README.myownquery courier-imap-1.3.12/authlib/README.myownquery --- courier-imap-1.3.12.orig/authlib/README.myownquery Thu Jan 1 01:00:00 1970 +++ courier-imap-1.3.12/authlib/README.myownquery Sun Dec 30 01:41:38 2001 @@ -0,0 +1,543 @@ + + + + + Developer Notes for courier-imap-myownquery.patch + + + + + document version: 1.03 + author: Pawel Wilk + + + + + + + + + + + + + + + + +0 What's that? + +1 Modifications overview + +2 Definitions + +3 New data types + 3.1 struct var_data + 3.2 typedef size_t (*parsefunc) + +4 New functions + 4.1 get_variable + 4.2 parse_core + 4.3 ParsePlugin_counter + 4.4 ParsePlugin_builder + 4.5 parse_string + 4.6 validate_password + 4.7 get_localpart + 4.8 get_domain + 4.9 parse_select_clause + 4.10 parse_chpass_clause + +5 Ideas and TODO + +6 Thanks + + + + + *----------------------- + 0 What's that? + *----------------------- + +Courier-imap-myownquery.patch allows administrator to set own MySQL queries +used by authdaemon to authenticate user (including fetchig credentials) and to +change user's password. It allows to construct SELECT or UPDATE clause in the +configuration file (authmysqlrc) by adding two new configuration variables: +MYSQL_SELECT_CLAUSE and MYSQL_CHPASS_CLAUSE. It may be useful in the mail +environments where there is such a need to have different database structure +and/or tables scheme than expected by authmysql module. + +It also implements a small parsing engine for substitution variables which +may appear in the clauses and are used to put informations like username +or domain into the right place of a query. + +This patch was created using `diff -Nur` on courier-imap-1.3.12 source. + + + + + + *----------------------- + 1 Modifications overview + *----------------------- + +Modified files: authmysqllib.c authmysqlrc + +Each modified set of instructions is marked by my e-mail address: +siefca@pld.org.pl + +Changes in the current source code are related to: + +- sections where the queries are constructed + (including memory allocation for the buffers) + + when MYSQL_SELECT_CLAUSE or MYSQL_CHPASS_CLAUSE is + used then the query goes through the parsing functions + passing over current memory allocation and query construction + subroutines + +- section where the configuration file is read + + i've had to modify read_env() function to allow line breaks + - now each sequence of the backslash as a first character and + newline as the second is replaced by two whitespaces while + putting into the buffer + +- sections where the query is constructed + + selection is made, depending on configuration variables which + are set or not - if own query is used + + + + + + *----------------------- + 2 Definitions + *----------------------- + +#define MAX_SUBSTITUTION_LEN 32 +#define SV_BEGIN_MARK "$(" +#define SV_END_MARK ")" +#define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1) +#define SV_END_LEN ((sizeof(SV_END_MARK))-1) + +These definitions allows to change substitution marks in an easy way. +SV_BEGIN_MARK refers to sequence of characters treated as a prefix of +each substitution variable and SV_END_MARK refers to string which is +a closing suffix. If the expected substitution variable is called +'local_part' (without apostrophes) then '$(local_part)' is a valid +string representation for SV_BEGIN_MARK set to "$(" and SV_END_MARK to ")". +MAX_SUBSTITUTION_LEN defines maximal length of a substitution variable's +identifier (name). + +The last two definitions are just for code simplification. + + + + + + + *----------------------- + 3 New data types + *----------------------- + +This section describes new data type definitions and variables. + +3.1 struct var_data + +struct var_data { + const char *name; + const char *value; + const size_t size; + size_t value_length; + } ; + +This structure holds information needed by parsing routines. +Using var_data array you may specify a set of string substitutions +which should be done while parsing a query. Last element in array +should have all fields set to zero (null). + +name field - should contain substituted variable name +value - should contain string which replaces it +size - should contain string size including the last zero byte ('\0') +value_length - should be set to zero - it is used as a value size cache + + +explanation: size is used to increase speed of calculation proccess + value_length is used to cache length of a value during the + parsing subroutines - it helps when substitution variable + occures more than once within the query + +Example: + +struct var_data vdt[] = { + {"some", "replacement", sizeof("some"), 0}, + {"anotha", NULL, sizeof("anotha"), 0}, + {NULL, NULL, 0, 0} +}; + +In this example we've declared that $(some) in the query should be +replaced by 'replacement' text, and replacement for $(anotha) will +be defined in the code before passing on the array pointer to +the paring function. + + +3.2 typedef size_t (*parsefunc) + +typedef int (*parsefunc)(const char *, size_t, void *); + +This type definition refers to the function pointer, which is used +to pass plugin functions into the core parsing subroutine. This definition +is included to simplify the declaration of the parse_core() function. + + + + + + *----------------------- + 4 New functions + *----------------------- + +This section describes added functions. + +4.1 get_variable + +NAME + + get_variable + +SYNOPSIS + + static const struct var_data *get_variable (const char *begin, + size_t len, + struct var_data *vdt); + +DESCRIPTION + + This function searches an array pointed by vdt and tries to find + the substitution variable, which name is identified with begin + pointer and length of len bytes long. + + This function is also responsible for updating length cache field + of vdt elements and validating requested variables. + + This function repports errors by sending human readable + messages to the standard error stream. + +RETURN VALUE + + This function returns a pointer to the array element which is + structure of var_data type, which contains variable definition + of a given name. It returns NULL on error or failure. + + +4.2 parse_core + +NAME + + parse_core + +SYNOPSIS + static int parse_core (const char *source, struct var_data *vdt, + parsefunc outfn, void *result); + +DESCRIPTION + + This is the parsing routine for query strings containing the + substitution variables. It reads the string pointed with source + and tries to catch a valid substitution variables or parts which + are plain text blocks. The main purpose of using this function + it to split source string into parts and for each part call + outfn() function. Those parts are substrings identified by + pointer to some element of the source string and size. + Those elements are the result of splitting source string into + logical parts: plain text substrings and substitution variables' + values. To get the values of any found substitution variables + parse_core() uses get_variable() function. To find places + where substitution variables occurs it uses strstr() function + in conjunction with SV_BEGIN_MARK and SV_END_MARK definitions. + It passes vdt structure pointer to get_variable() function if + it calls it. + + outfn() function should be passed by its pointer which + refers to declaration: + + int (*outfn) (const char *begin, + size_t string_length, + void *void_pointer); + + Each time outfn() is called the result argument of parse_core() + is passed to the outfn() as a last argument (void_pointer). + + Example: + + Example string "$(local_part) AND $(domain)" will cause the + outfn() to be called 3 times. First time for a value of + $(local_part) substitution variable, second time + for " AND " string, and the last time for $(domain) variable's + value. Variables are passed to outfn() by their (found) values, + plain text blocks are passed as they appear. + + This function repports errors by sending human readable + messages to the standard error stream. + +RETURN VALUE + + This function returns -1 if an error has occured and 0 if + everything went good. + +4.3 ParsePlugin_counter + +NAME + + ParsePlugin_counter + +SYNOPSIS + + int ParsePlugin_counter (const char *begin, size_t len, + void *vp); + +DESCRIPTION + + This is parsing plugin function. It simply increments the value + found in the memory area pointed by vp. It assumes that + the memory area is allocated for the variable of size_t + type and that area was passed by (size_t *) pointer. + The value is incremented by len argument. Begin argument + is not used. + + This function repports errors by sending human readable + messages to the standard error stream. + +RETURN VALUE + + This function returns the variable size or -1 if an error + has occured, 0 if everything went good. + +4.4 ParsePlugin_builder + +NAME + + ParsePlugin_builder + +SYNOPSIS + + int ParsePlugin_builder (const char *begin, size_t len, + void *vp); + +DESCRIPTION + + This is parsing plugin function. It simply copies len bytes + of a string pointed by begin to the end of memory area pointed by + vp. It assumes that the area pointed by vp is passed by (char **) + type pointer and refers to the (char *) pointer variable. + After each call it shifts the value of pointer variable (char *) + incrementing it by len bytes. Be careful when using this function + - its changes the given pointer value. Always operate on an + additional pointer type variable when passing it as the third + argument. + +RETURN VALUE + + This function returns the variable size or -1 if an error + has occured, 0 if everything went good. + +4.5 parse_string + +NAME + parse_string + +SYNOPSIS + + static char *parse_string (const char *source, struct var_data *vdt); + +DESCRIPTION + + This function parses the string pointed with source according to the + replacement instructions set in var_data array, which is passed with + its pointer vdt. It produces changed string located in newly allocated + memory area. + + This function calls parse_core() function with various parsing + subroutines passed as function pointers. + + 1. It uses parse_core() with ParsePlugin_counter to obtain the + total amount of memory needed for the output string. + + 2. It allocates the memory. + + 3. It uses parse_core() with ParsePlugin_builder to build the + output string. + + This function repports errors by sending human readable + messages to the standard error stream. + +RETURN VALUE + + Function returns pointer to the result buffer or NULL + if an error has occured. + +WARNINGS + + This function allocates some amount of memory using standard + ANSI C routines. Memory allocated by this function should be + freed with free(). + + +4.6 validate_password + +NAME + validate_password + +SYNOPSIS + + static const char *validate_password (const char *password); + +DESCRIPTION + + This function checks whether password string does contain + any dangerous characters, which may be used to pass command + strings to the database connection stream. If it founds one + it replaces it by the backslash character. + +RETURN VALUE + + It returns a pointer to the static buffer which contains + validated password string or NULL if an error has occured. + + +4.7 get_localpart + +NAME + + get_localpart + +SYNOPSIS + + static const char *get_localpart (const char *username); + +DESCRIPTION + + This function detaches local part of an e-mail address + from string pointed with username and puts it to the + buffer of the fixed length. All necessary cleaning is + made on the result string. + +RETURN VALUE + + Pointer to the static buffer containing local part or + NULL if there was some error. + + +4.8 get_domain + +NAME + + get_domain + +SYNOPSIS + + static const char *get_domain (const char *username, + const char *defdomain); + +DESCRIPTION + + This function detaches domain part of an e-mail address + from string pointed with username and puts it to the + buffer of the fixed length. All necessary cleaning is + made on the result string. If function cannot find domain + part in the string the string pointed by defdomain is + used instead. + +RETURN VALUE + + Pointer to the static buffer containing domain name or + NULL if there was some error. + + +4.9 parse_select_clause + +NAME + + parse_select_clause + +SYNOPSIS + + static char *parse_select_clause (const char *clause, + const char *username, + const char *defdomain); + +DESCRIPTION + + This function is a simple wrapper to the parse_string() + function. It parses a query pointed by caluse. username + and defdomain strings are used to replace corresponding + substitution strings if present in the query: $(local_part) + and $(domain). + + +RETURN VALUE + + Same as parse_string(). + + +4.10 parse_chpass_clause + +NAME + + parse_chpass_clause + +SYNOPSIS + + static char *parse_chpass_clause (const char *clause, + const char *username, + const char *defdomain, + const char *newpass, + const char *newpass_crypt); + +DESCRIPTION + + This function is a simple wrapper to the parse_string() + function. It parses a query pointed by caluse. username, + defdomain, newpass and newpass_crypt strings are used to + replace corresponding substitution strings if present in + the query: $(local_part), $(domain), $(newpass), + $(newpass_crypt). + +RETURN VALUE + + Same as parse_string(). + + + + + + *------------------------ + 5 Ideas and TODO + *------------------------ + +- solve problem with fixed buffer length of local part and the domain part + strings after split (problem?) +- allow admin to set a group name instead of numerical group id +- allow admin to set a username instead of numerical user id + +- add clauses: + + - MYSQL_PRESELECT_CLAUSE (query which comes before MYSQL_SELECT_CLAUSE) + - MYSQL_POSTSELECT_CLAUSE (query which comes after MYSQL_SELECT_CLAUSE) + + + + + + *------------------------ + 6 Thanks + *------------------------ + +At the beginning this patch was messy indeed. :> I would like to thank +Sam Varshavchik for pointing me a lot how to make it more fast and solid. +I would also thank Philip Hazel, Chris Lightfoot and Mike Bremford which +by their software capabilities inspired me to write it. + +--------------------------------------------------------------------------- + diff -Nur courier-imap-1.3.12.orig/authlib/authmysqllib.c courier-imap-1.3.12/authlib/authmysqllib.c --- courier-imap-1.3.12.orig/authlib/authmysqllib.c Mon Aug 6 05:12:39 2001 +++ courier-imap-1.3.12/authlib/authmysqllib.c Sun Dec 30 01:41:00 2001 @@ -3,7 +3,6 @@ ** distribution information. */ - #include #include #include @@ -18,8 +17,26 @@ #include "authmysqlrc.h" #include "auth.h" +/* siefca@pld.org.pl */ +#define MAX_SUBSTITUTION_LEN 32 +#define SV_BEGIN_MARK "$(" +#define SV_END_MARK ")" +#define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1) +#define SV_END_LEN ((sizeof(SV_END_MARK))-1) + static const char rcsid[]="$Id: authmysqllib.c,v 1.14 2001/08/01 22:23:01 mrsam Exp $"; +/* siefca@pld.org.pl */ +struct var_data { + const char *name; + const char *value; + const size_t size; + size_t value_length; + } ; + +/* siefca@pld.org.pl */ +typedef int (*parsefunc)(const char *, size_t, void *); + static const char *read_env(const char *env) { static char *mysqlauth=0; @@ -51,7 +68,13 @@ for (i=0; i MAX_SUBSTITUTION_LEN) + { + fprintf (stderr, "authmysql: variable name too long " + "while parsing substitution\n" + "authmysql: name begins with " + SV_BEGIN_MARK + "%.*s...\n", MAX_SUBSTITUTION_LEN, begin); + return NULL; + } + + for (vdp=vdt; vdp->name; vdp++) + if (vdp->size == len+1 && + !strncmp(begin, vdp->name, len)) + { + if (!vdp->value) + vdp->value = ""; + if (!vdp->value_length) /* length cache */ + vdp->value_length = strlen (vdp->value); + return vdp; + } + + fprintf (stderr, "authmysql: unknown substitution variable " + SV_BEGIN_MARK + "%.*s" + SV_END_MARK + "\n", len, begin); + + return NULL; +} + +/* siefca@pld.org.pl */ +static int ParsePlugin_counter (const char *p, size_t length, void *vp) +{ + if (!p || !vp || length < 0) + { + fprintf (stderr, "authmysql: bad arguments while counting " + "query string\n"); + return -1; + } + + *((size_t *)vp) += length; + + return 0; +} + +/* siefca@pld.org.pl */ +static int ParsePlugin_builder (const char *p, size_t length, void *vp) +{ +char **strptr = (char **) vp; + + if (!p || !vp || length < 0) + { + fprintf (stderr, "authmysql: bad arguments while building " + "query string\n"); + return -1; + } + + if (!length) return 0; + memcpy ((void *) *strptr, (void *) p, length); + *strptr += length; + + return 0; +} + +/* siefca@pld.org.pl */ +static int parse_core (const char *source, struct var_data *vdt, + parsefunc outfn, void *result) +{ +size_t v_size = 0, + t_size = 0; +const char *p, *q, *e, + *v_begin, *v_end, + *t_begin, *t_end; +struct var_data *v_ptr; + + + if (!source) + source = ""; + if (!result) + { + fprintf (stderr, "authmysql: no memory allocated for result" + "while parser core was invoked\n"); + return -1; + } + if (!vdt) + { + fprintf (stderr, "authmysql: no substitution table found " + "while parser core was invoked\n"); + return -1; + } + + q = source; + while ( (p=strstr(q, SV_BEGIN_MARK)) ) + { + e = strstr (p, SV_END_MARK); + if (!e) + { + fprintf (stderr, "authmysql: syntax error in " + "substitution " + "- no closing symbol fould!\n" + "authmysql: bad variable begins with:" + "%.*s...\n", MAX_SUBSTITUTION_LEN, p); + return -1; + } + + /* + ** + ** __________sometext$(variable_name)_________ + ** | | | | + ** t_begin' t_end' `v_begin `v_end + ** + */ + + v_begin = p+SV_BEGIN_LEN; /* variable field ptr */ + v_end = e-SV_END_LEN; /* variable field last character */ + v_size = v_end-v_begin+1;/* variable field length */ + + t_begin = q; /* text field ptr */ + t_end = p-1; /* text field last character */ + t_size = t_end-t_begin+1;/* text field length */ + + /* work on text */ + if ( (outfn (t_begin, t_size, result)) == -1 ) + return -1; + + /* work on variable */ + v_ptr = get_variable (v_begin, v_size, vdt); + if (!v_ptr) return -1; + + if ( (outfn (v_ptr->value, v_ptr->value_length, result)) == -1 ) + return -1; + + q = e + 1; + } + + /* work on last part of text if any */ + if (*q != '\0') + if ( (outfn (q, strlen(q), result)) == -1 ) + return -1; + + return 0; +} + +/* siefca@pld.org.pl */ +static char *parse_string (const char *source, struct var_data *vdt) +{ +struct var_data *vdp = NULL; +char *output_buf = NULL, + *pass_buf = NULL; +size_t buf_size = 2; + + if (source == NULL || *source == '\0' || + vdt == NULL || vdt[0].name == NULL) + { + fprintf (stderr, "authmysql: source clause is empty " + "- this is critical error\n"); + return NULL; + } + + /* zero var_data length cache - important! */ + for (vdp=vdt; vdp->name; vdp++) + vdp->value_length = 0; + + /* phase 1 - count and validate string */ + if ( (parse_core (source, vdt, &ParsePlugin_counter, &buf_size)) != 0) + return NULL; + + /* phase 2 - allocate memory */ + output_buf = malloc (buf_size); + if (!output_buf) + { perror ("malloc"); return NULL; } + + pass_buf = output_buf; + + /* phase 3 - build the output string */ + if ( (parse_core (source, vdt, &ParsePlugin_builder, &pass_buf)) != 0) + { free (output_buf); return NULL; } + + *pass_buf = '\0'; + return output_buf; +} + +/* siefca@pld.org.pl */ +static const char *get_localpart (const char *username) +{ +size_t lbuf = 0; +const char *l_end, *p; +char *q; +static char localpart_buf[130]; + + if (!username || *username == '\0') return NULL; + + p = strchr(username,'@'); + if (p) + { + if ((p-username) > 128) + return NULL; + l_end = p; + } + else + { + if ((lbuf = strlen(username)) > 128) + return NULL; + l_end = username + lbuf; + } + + p=username; + q=localpart_buf; + + while (*p && p != l_end) + if (*p == '\"' || *p == '\\' || + *p == '\'' || (int)(unsigned char)*p < ' ') + p++; + else + *q++ = *p++; + + *q = '\0'; + return localpart_buf; +} + +/* siefca@pld.org.pl */ +static const char *get_domain (const char *username, const char *defdomain) +{ +static char domain_buf[260]; +const char *p; +char *q; + + if (!username || *username == '\0') return NULL; + p = strchr(username,'@'); + + if (!p || *(p+1) == '\0') + { + if (defdomain && *defdomain) + return defdomain; + else + return NULL; + } + + p++; + if ((strlen(p)) > 256) + return NULL; + + q = domain_buf; + while (*p) + if (*p == '\"' || *p == '\\' || + *p == '\'' || (int)(unsigned char)*p < ' ') + p++; + else + *q++ = *p++; + + *q = '\0'; + return domain_buf; +} + +/* siefca@pld.org.pl */ +static const char *validate_password (const char *password) +{ +static char pass_buf[260]; +const char *p; +char *q; + + if (!password || *password == '\0' || (strlen(password)) > 256) + return NULL; + + p = password; + q = pass_buf; + + while (*p) + if (*p == '\"' || *p == '\\' || *p == '\'') + *q++ = '\\'; + else + *q++ = *p++; + + *q = '\0'; + return pass_buf; +} + + +/* siefca@pld.org.pl */ +static char *parse_select_clause (const char *clause, const char *username, + const char *defdomain) +{ +static struct var_data vd[]={ + {"local_part", NULL, sizeof("local_part"), 0}, + {"domain", NULL, sizeof("domain"), 0}, + {NULL, NULL, 0, 0}}; + + if (clause == NULL || *clause == '\0' || + !username || *username == '\0') + return NULL; + + vd[0].value = get_localpart (username); + vd[1].value = get_domain (username, defdomain); + if (!vd[0].value || !vd[1].value) + return NULL; + + return (parse_string (clause, vd)); +} + +/* siefca@pld.org.pl */ +static char *parse_chpass_clause (const char *clause, const char *username, + const char *defdomain, const char *newpass, + const char *newpass_crypt) +{ +static struct var_data vd[]={ + {"local_part", NULL, sizeof("local_part"), 0}, + {"domain", NULL, sizeof("domain"), 0}, + {"newpass", NULL, sizeof("newpass"), 0}, + {"newpass_crypt", NULL, sizeof("newpass_crypt"), 0}, + {NULL, NULL, 0, 0}}; + + if (clause == NULL || *clause == '\0' || + !username || *username == '\0' || + !newpass || *newpass == '\0' || + !newpass_crypt || *newpass_crypt == '\0') return NULL; + + vd[0].value = get_localpart (username); + vd[1].value = get_domain (username, defdomain); + vd[2].value = validate_password (newpass); + vd[3].value = validate_password (newpass_crypt); + + if (!vd[0].value || !vd[1].value || + !vd[2].value || !vd[3].value) return NULL; + + return (parse_string (clause, vd)); +} + struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username) { -const char *user_table; -const char *defdomain; +const char *user_table =NULL; +const char *defdomain =NULL; char *querybuf, *p; MYSQL_ROW row; MYSQL_RES *result; -const char *crypt_field, *clear_field, *maildir_field, *home_field, - *name_field, - *login_field, *uid_field, *gid_field, *quota_field, *where_clause; +const char *crypt_field =NULL, + *clear_field =NULL, + *maildir_field =NULL, + *home_field =NULL, + *name_field =NULL, + *login_field =NULL, + *uid_field =NULL, + *gid_field =NULL, + *quota_field =NULL, + *where_clause =NULL, + *select_clause =NULL; /* siefca@pld.org.pl */ static const char query[]= "SELECT %s, %s, %s, %s, %s, %s, %s, %s, %s FROM %s WHERE %s = \""; @@ -232,79 +608,95 @@ free(ui.fullname); memset(&ui, 0, sizeof(ui)); - user_table=read_env("MYSQL_USER_TABLE"); - defdomain=read_env("DEFAULT_DOMAIN"); - - if (!user_table) + select_clause=read_env("MYSQL_SELECT_CLAUSE"); + defdomain=read_env("DEFAULT_DOMAIN"); + + if (!select_clause) /* siefca@pld.org.pl */ { - fprintf(stderr, "authmysql: MYSQL_USER_TABLE not set in " - AUTHMYSQLRC ".\n"); - return (0); - } + user_table=read_env("MYSQL_USER_TABLE"); - crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); - clear_field=read_env("MYSQL_CLEAR_PWFIELD"); - name_field=read_env("MYSQL_NAME_FIELD"); + if (!user_table) + { + fprintf(stderr, "authmysql: MYSQL_USER_TABLE not set in " + AUTHMYSQLRC ".\n"); + return (0); + } - if (!crypt_field && !clear_field) - { - fprintf(stderr, - "authmysql: MYSQL_CRYPT_PWFIELD and " - "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC ".\n"); - return (0); - } - if (!crypt_field) crypt_field="\"\""; - if (!clear_field) clear_field="\"\""; - if (!name_field) name_field="\"\""; + crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); + clear_field=read_env("MYSQL_CLEAR_PWFIELD"); + name_field=read_env("MYSQL_NAME_FIELD"); + + if (!crypt_field && !clear_field) + { + fprintf(stderr, + "authmysql: MYSQL_CRYPT_PWFIELD and " + "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC ".\n"); + return (0); + } + if (!crypt_field) crypt_field="\"\""; + if (!clear_field) clear_field="\"\""; + if (!name_field) name_field="\"\""; - uid_field = read_env("MYSQL_UID_FIELD"); - if (!uid_field) uid_field = "uid"; + uid_field = read_env("MYSQL_UID_FIELD"); + if (!uid_field) uid_field = "uid"; - gid_field = read_env("MYSQL_GID_FIELD"); - if (!gid_field) gid_field = "gid"; + gid_field = read_env("MYSQL_GID_FIELD"); + if (!gid_field) gid_field = "gid"; - login_field = read_env("MYSQL_LOGIN_FIELD"); - if (!login_field) login_field = "id"; + login_field = read_env("MYSQL_LOGIN_FIELD"); + if (!login_field) login_field = "id"; - home_field = read_env("MYSQL_HOME_FIELD"); - if (!home_field) home_field = "home"; + home_field = read_env("MYSQL_HOME_FIELD"); + if (!home_field) home_field = "home"; - maildir_field=read_env("MYSQL_MAILDIR_FIELD"); - if (!maildir_field) maildir_field="\"\""; + maildir_field=read_env("MYSQL_MAILDIR_FIELD"); + if (!maildir_field) maildir_field="\"\""; - quota_field=read_env("MYSQL_QUOTA_FIELD"); - if (!quota_field) quota_field="\"\""; + quota_field=read_env("MYSQL_QUOTA_FIELD"); + if (!quota_field) quota_field="\"\""; - where_clause=read_env("MYSQL_WHERE_CLAUSE"); - if (!where_clause) where_clause = ""; + where_clause=read_env("MYSQL_WHERE_CLAUSE"); + if (!where_clause) where_clause = ""; + } if (!defdomain) defdomain=""; - querybuf=malloc(sizeof(query) + 100 + strlen(user_table) + strlen(defdomain) - + strlen(crypt_field) + strlen(clear_field) + strlen(maildir_field) - + strlen(uid_field) + strlen(gid_field) + 2 * strlen(login_field) - + strlen(home_field) + strlen(quota_field) + strlen(where_clause) - + strlen(name_field)); - if (!querybuf) + if (!select_clause) /* siefca@pld.org.pl */ { - perror("malloc"); - return (0); - } + querybuf=malloc(sizeof(query) + 100 + strlen(user_table) + strlen(defdomain) + + strlen(crypt_field) + strlen(clear_field) + strlen(maildir_field) + + strlen(uid_field) + strlen(gid_field) + 2 * strlen(login_field) + + strlen(home_field) + strlen(quota_field) + strlen(where_clause) + + strlen(name_field)); + + if (!querybuf) + { + perror("malloc"); + return (0); + } + + sprintf(querybuf, query, login_field, crypt_field, clear_field, + uid_field, gid_field, home_field, maildir_field, quota_field, + name_field, user_table, login_field); - sprintf(querybuf, query, login_field, crypt_field, clear_field, - uid_field, gid_field, home_field, maildir_field, quota_field, - name_field, user_table, login_field); - p=querybuf+strlen(querybuf); + p=querybuf+strlen(querybuf); - append_username(p, username, defdomain); - strcat(p, "\""); + append_username(p, username, defdomain); + strcat(p, "\""); - if (strcmp(where_clause, "")) { - strcat(p, " AND ("); - strcat(p, where_clause); - strcat(p, ")"); + if (strcmp(where_clause, "")) { + strcat(p, " AND ("); + strcat(p, where_clause); + strcat(p, ")"); + } } - + else + { + /* siefca@pld.org.pl */ + querybuf=parse_select_clause (select_clause, username, defdomain); + if (!querybuf) return 0; + } + if (mysql_query (mysql, querybuf)) { /* */ @@ -379,12 +771,13 @@ const char *comma; int rc=0; - const char *clear_field; - const char *crypt_field; - const char *defdomain; - const char *where_clause; - const char *user_table; - const char *login_field; + const char *clear_field =NULL, + *crypt_field =NULL, + *defdomain =NULL, + *where_clause =NULL, + *user_table =NULL, + *login_field =NULL, + *chpass_clause =NULL; /* siefca@pld.org.pl */ if (!mysql) return (-1); @@ -412,21 +805,34 @@ ++l; } - login_field = read_env("MYSQL_LOGIN_FIELD"); - if (!login_field) login_field = "id"; - crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); - clear_field=read_env("MYSQL_CLEAR_PWFIELD"); + /* siefca@pld.org.pl */ + chpass_clause=read_env("MYSQL_CHPASS_CLAUSE"); defdomain=read_env("DEFAULT_DOMAIN"); - where_clause=read_env("MYSQL_WHERE_CLAUSE"); user_table=read_env("MYSQL_USER_TABLE"); - - sql_buf=malloc(strlen(crypt_field ? crypt_field:"") - + strlen(clear_field ? clear_field:"") - + strlen(defdomain ? defdomain:"") - + strlen(login_field) + l + strlen(newpass_crypt) - + strlen(user_table) - + strlen(where_clause ? where_clause:"") - + 200); + if (!chpass_clause) + { + login_field = read_env("MYSQL_LOGIN_FIELD"); + if (!login_field) login_field = "id"; + crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); + clear_field=read_env("MYSQL_CLEAR_PWFIELD"); + where_clause=read_env("MYSQL_WHERE_CLAUSE"); + sql_buf=malloc(strlen(crypt_field ? crypt_field:"") + + strlen(clear_field ? clear_field:"") + + strlen(defdomain ? defdomain:"") + + strlen(login_field) + l + strlen(newpass_crypt) + + strlen(user_table) + + strlen(where_clause ? where_clause:"") + + 200); + } + else + { + sql_buf=parse_chpass_clause(chpass_clause, + user, + defdomain, + pass, + newpass_crypt); + } + if (!sql_buf) { @@ -434,53 +840,57 @@ return (-1); } - sprintf(sql_buf, "UPDATE %s SET", user_table); - - comma=""; - - if (clear_field && *clear_field) + if (!chpass_clause) /*siefca@pld.org.pl */ { - char *q; + sprintf(sql_buf, "UPDATE %s SET", user_table); - strcat(strcat(strcat(sql_buf, " "), clear_field), - "=\""); + comma=""; - q=sql_buf+strlen(sql_buf); - while (*pass) + if (clear_field && *clear_field) { - if (*pass == '"' || *pass == '\\') - *q++= '\\'; - *q++ = *pass++; + char *q; + + strcat(strcat(strcat(sql_buf, " "), clear_field), + "=\""); + + q=sql_buf+strlen(sql_buf); + while (*pass) + { + if (*pass == '"' || *pass == '\\') + *q++= '\\'; + *q++ = *pass++; + } + strcpy(q, "\""); + comma=", "; } - strcpy(q, "\""); - comma=", "; - } - if (crypt_field && *crypt_field) - { - strcat(strcat(strcat(strcat(strcat(strcat(sql_buf, comma), - " "), - crypt_field), - "=\""), - newpass_crypt_ptr), - "\""); - } - free(newpass_crypt); + if (crypt_field && *crypt_field) + { + strcat(strcat(strcat(strcat(strcat(strcat(sql_buf, comma), + " "), + crypt_field), + "=\""), + newpass_crypt_ptr), + "\""); + } + free(newpass_crypt); - strcat(strcat(strcat(sql_buf, " WHERE "), - login_field), - "=\""); + strcat(strcat(strcat(sql_buf, " WHERE "), + login_field), + "=\""); - append_username(sql_buf+strlen(sql_buf), user, defdomain); + append_username(sql_buf+strlen(sql_buf), user, defdomain); - strcat(sql_buf, "\""); + strcat(sql_buf, "\""); - if (where_clause && *where_clause) - { - strcat(sql_buf, " AND ("); - strcat(sql_buf, where_clause); - strcat(sql_buf, ")"); - } + if (where_clause && *where_clause) + { + strcat(sql_buf, " AND ("); + strcat(sql_buf, where_clause); + strcat(sql_buf, ")"); + } + + } /* end of: if (!chpass_clause) */ if (mysql_query (mysql, sql_buf)) { diff -Nur courier-imap-1.3.12.orig/authlib/authmysqlrc courier-imap-1.3.12/authlib/authmysqlrc --- courier-imap-1.3.12.orig/authlib/authmysqlrc Sun Oct 7 18:32:56 2001 +++ courier-imap-1.3.12/authlib/authmysqlrc Fri Dec 28 02:08:01 2001 @@ -141,4 +141,65 @@ # # MYSQL_WHERE_CLAUSE server='mailhost.example.com' - +##NAME: MYSQL_SELECT_CLAUSE:0 +# +# (EXPERIMENTAL) +# This is optional, MYSQL_SELECT_CLAUSE can be set when you have a database, +# which is structuraly different from proposed. The fixed string will +# be used to do a SELECT operation on database, which should return fields +# in order specified bellow: +# +# username, cryptpw, clearpw, uid, gid, home, maildir, quota, fullname +# +# Enabling this option causes ignorance of any other field-related +# options, excluding default domain. +# +# There are two variables, which you can use. Substitution will be made +# for them, so you can put entered username (local part) and domain name +# in the right place of your query. These variables are: +# $(local_part) and $(domain) +# +# If a $(domain) is empty (not given by the remote user) the default domain +# name is used in its place. +# +# This example is a little bit modified adaptation of vmail-sql +# database scheme: +# +# MYSQL_SELECT_CLAUSE SELECT popbox.local_part, \ +# CONCAT('{MD5}', popbox.password_hash), \ +# popbox.clearpw, \ +# domain.uid, \ +# domain.gid, \ +# CONCAT(domain.path, '/', popbox.mbox_name), \ +# '', \ +# domain.quota, \ +# '', \ +# FROM popbox, domain \ +# WHERE popbox.local_part = '$(local_part)' \ +# AND popbox.domain_name = '$(domain)' \ +# AND popbox.domain_name = domain.domain_name +# +##NAME: MYSQL_CHPASS_CLAUSE:0 +# +# (EXPERIMENTAL) +# This is optional, MYSQL_CHPASS_CLAUSE can be set when you have a database, +# which is structuraly different from proposed. The fixed string will +# be used to do an UPDATE operation on database. In other words, it is +# used, when changing password. +# +# There are four variables, which you can use. Substitution will be made +# for them, so you can put entered username (local part) and domain name +# in the right place of your query. There variables are: +# $(local_part) , $(domain) , $(newpass) , $(newpass_crypt) +# +# If a $(domain) is empty (not given by the remote user) the default domain +# name is used in its place. +# $(newpass) contains plain password +# $(newpass_crypt) contains its crypted form +# +# MYSQL_CHPASS_CLAUSE UPDATE popbox \ +# SET clearpw='$(newpass)', \ +# password_hash='$(newpass_crypt)' \ +# WHERE local_part='$(local_part)' \ +# AND domain_name='$(domain)' +#