Imported Debian patch 0.66.1-1
[hcoop/debian/courier-authlib.git] / authgetconfig.c
diff --git a/authgetconfig.c b/authgetconfig.c
new file mode 100644 (file)
index 0000000..6e76ba0
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+** Copyright 2012 Double Precision, Inc.  See COPYING for
+** distribution information.
+*/
+
+#if    HAVE_CONFIG_H
+#include       "courier_auth_config.h"
+#endif
+#include       "auth.h"
+#include       "courierauthdebug.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static const char *configfilename=0;
+static char *configauth=0;
+static size_t configauth_size=0;
+
+#define err courier_auth_err
+
+const char *authgetconfig(const char *filename, const char *env)
+{
+       size_t  i;
+       char    *p=0;
+       int     l=strlen(env);
+
+       if (configfilename && strcmp(filename, configfilename))
+       {
+               if (configauth)
+                       free(configauth);
+               configauth=0;
+               configauth_size=0;
+       }
+
+       configfilename=filename;
+
+       if (!configauth)
+       {
+               FILE    *f=fopen(filename, "r");
+               struct  stat    buf;
+
+               if (!f) return (0);
+               if (fstat(fileno(f), &buf) ||
+                       (configauth=malloc(buf.st_size+2)) == 0)
+               {
+                       fclose(f);
+                       return (0);
+               }
+               if (fread(configauth, buf.st_size, 1, f) != 1)
+               {
+                       free(configauth);
+                       configauth=0;
+                       fclose(f);
+                       return (0);
+               }
+               configauth[configauth_size=buf.st_size]=0;
+
+               for (i=0; i<configauth_size; i++)
+                       if (configauth[i] == '\n')
+                       {       /* siefca@pld.org.pl */
+                               if (!i || configauth[i-1] != '\\')
+                               {
+                                       configauth[i]='\0';
+                               }
+                               else
+                               {
+                                       configauth[i]=configauth[i-1]= ' ';
+                               }
+                       }
+               fclose(f);
+       }
+
+       for (i=0; i<configauth_size; )
+       {
+               p=configauth+i;
+               if (memcmp(p, env, l) == 0 &&
+                       isspace((int)(unsigned char)p[l]))
+               {
+                       p += l;
+                       while (*p && *p != '\n' &&
+                               isspace((int)(unsigned char)*p))
+                               ++p;
+                       break;
+               }
+
+               while (i < configauth_size)
+                       if (configauth[i++] == 0)       break;
+       }
+
+       if (i < configauth_size)
+               return (p);
+       return (0);
+}
+
+/* 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)
+
+/* 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 *);
+
+/* siefca@pld.org.pl */
+static struct var_data *get_variable (const char *begin, size_t len,
+                                     struct var_data *vdt)
+{
+struct var_data *vdp;
+
+       if (!begin || !vdt) /* should never happend */
+       {
+               err("get_variable: critical error while "
+                                "parsing substitution variable");
+               return NULL;
+       }
+       if (len < 1)
+       {
+               err("get_variable: unknown empty substitution "
+                                "variable - aborting");
+               return NULL;
+       }
+       if (len > MAX_SUBSTITUTION_LEN)
+       {
+               err("get_variable: variable name too long "
+                                "while parsing substitution. "
+                                "name begins with "
+                                SV_BEGIN_MARK
+                                "%.*s...", 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;
+               }
+       
+       err("get_variable: unknown substitution variable "
+                        SV_BEGIN_MARK
+                        "%.*s"
+                        SV_END_MARK
+                        , (int)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)
+       {
+               err("get_variable: bad arguments while counting "
+                                "query string");
+               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)
+       {
+               err("get_variable: bad arguments while building "
+                                "query string");
+               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)
+       {
+               err("auth_parse: no memory allocated for result "
+                                "while parser core was invoked");
+               return -1;
+       }
+       if (!vdt)
+       {
+               err("auth_parse: no substitution table found "
+                                "while parser core was invoked");
+               return -1;
+       }
+       
+       q = source;
+       while ( (p=strstr(q, SV_BEGIN_MARK)) )
+       {
+               e = strstr (p, SV_END_MARK);
+               if (!e)
+               {
+                       err("auth_parse: syntax error in "
+                                        "substitution "
+                                        "- no closing symbol found! "
+                                        "bad variable begins with:"
+                                        "%.*s...", 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)
+       {
+               err("auth_parse: source clause is empty "
+                      "- this is critical error");
+               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;
+}
+
+static char *local_part_escaped(const char *username,
+                               char *(*escape_func)(const char *, size_t))
+{
+       const char *p=strchr(username, '@');
+       size_t n=p ? p-username:strlen(username);
+
+       return escape_func(username, n);
+}
+
+static char *domain_part_escaped(const char *username,
+                                const char *defdomain,
+                                char *(*escape_func)(const char *, size_t))
+{
+       const char *p=strchr(username, '@');
+       size_t n;
+
+       if (p)
+               ++p;
+       else
+               p=defdomain;
+
+       n=strlen(p);
+
+       return escape_func(p, n);
+}
+
+static int local_and_domain_part_escaped(char *(*escape_func)(const char *, size_t),
+                                        const char *username,
+                                        const char *defdomain,
+                                        char **local_ret,
+                                        char **domain_ret)
+{
+       if ((*local_ret=local_part_escaped(username, escape_func)) == NULL)
+               return 0;
+
+       if ((*domain_ret=domain_part_escaped(username, defdomain,
+                                            escape_func)) == NULL)
+       {
+               free(*local_ret);
+               return 0;
+       }
+
+       return 1;
+}
+
+/* siefca@pld.org.pl */
+char *auth_parse_select_clause (char *(*escape_func)(const char *, size_t),
+                               const char *clause, const char *username,
+                               const char *defdomain,
+                               const char *service)
+{
+       char *str;
+
+       static struct var_data vd[]={
+               {"local_part",  NULL,   sizeof("local_part"),   0},
+               {"domain",              NULL,   sizeof("domain"),       0},
+               {"service",             NULL,   sizeof("service"),      0},
+               {NULL,          NULL,   0,                      0}};
+
+       char *l_part;
+       char *d_part;
+
+       if (clause == NULL || *clause == '\0' ||
+           !username || *username == '\0')
+               return NULL;
+
+       if (!local_and_domain_part_escaped(escape_func,
+                                          username, defdomain,
+                                          &l_part, &d_part))
+               return NULL;
+
+       vd[0].value=l_part;
+       vd[1].value=d_part;
+       vd[2].value     = service;
+
+       str=parse_string (clause, vd);
+       free(l_part);
+       free(d_part);
+       return str;
+}
+
+/* siefca@pld.org.pl */
+char *auth_parse_chpass_clause (char *(*escape_func)(const char *, size_t),
+                               const char *clause, const char *username,
+                               const char *defdomain, const char *newpass,
+                               const char *newpass_crypt)
+{
+       char *str;
+
+       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}};
+       char *l_part;
+       char *d_part;
+
+       if (clause == NULL || *clause == '\0'           ||
+           !username || *username == '\0'              ||
+           !newpass || *newpass == '\0'                ||
+           !newpass_crypt || *newpass_crypt == '\0')   return NULL;
+
+       if (!local_and_domain_part_escaped(escape_func,
+                                          username, defdomain,
+                                          &l_part, &d_part))
+               return NULL;
+
+       vd[0].value=l_part;
+       vd[1].value=d_part;
+       vd[2].value     = newpass;
+       vd[3].value     = newpass_crypt;
+       
+       if (!vd[0].value || !vd[1].value ||
+           !vd[2].value || !vd[3].value)
+       {
+               free(l_part);
+               free(d_part);
+               return NULL;
+       }
+
+       str=parse_string (clause, vd);
+       free(l_part);
+       free(d_part);
+       return str;
+}