Backport to wheezy
[hcoop/debian/courier-authlib.git] / authgetconfig.c
CommitLineData
b0322a85
CE
1/*
2** Copyright 2012 Double Precision, Inc. See COPYING for
3** distribution information.
4*/
5
6#if HAVE_CONFIG_H
7#include "courier_auth_config.h"
8#endif
9#include "auth.h"
10#include "courierauthdebug.h"
11#include <string.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <ctype.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17
18static const char *configfilename=0;
19static char *configauth=0;
20static size_t configauth_size=0;
21
22#define err courier_auth_err
23
24const char *authgetconfig(const char *filename, const char *env)
25{
26 size_t i;
27 char *p=0;
28 int l=strlen(env);
29
30 if (configfilename && strcmp(filename, configfilename))
31 {
32 if (configauth)
33 free(configauth);
34 configauth=0;
35 configauth_size=0;
36 }
37
38 configfilename=filename;
39
40 if (!configauth)
41 {
42 FILE *f=fopen(filename, "r");
43 struct stat buf;
44
45 if (!f) return (0);
46 if (fstat(fileno(f), &buf) ||
47 (configauth=malloc(buf.st_size+2)) == 0)
48 {
49 fclose(f);
50 return (0);
51 }
52 if (fread(configauth, buf.st_size, 1, f) != 1)
53 {
54 free(configauth);
55 configauth=0;
56 fclose(f);
57 return (0);
58 }
59 configauth[configauth_size=buf.st_size]=0;
60
61 for (i=0; i<configauth_size; i++)
62 if (configauth[i] == '\n')
63 { /* siefca@pld.org.pl */
64 if (!i || configauth[i-1] != '\\')
65 {
66 configauth[i]='\0';
67 }
68 else
69 {
70 configauth[i]=configauth[i-1]= ' ';
71 }
72 }
73 fclose(f);
74 }
75
76 for (i=0; i<configauth_size; )
77 {
78 p=configauth+i;
79 if (memcmp(p, env, l) == 0 &&
80 isspace((int)(unsigned char)p[l]))
81 {
82 p += l;
83 while (*p && *p != '\n' &&
84 isspace((int)(unsigned char)*p))
85 ++p;
86 break;
87 }
88
89 while (i < configauth_size)
90 if (configauth[i++] == 0) break;
91 }
92
93 if (i < configauth_size)
94 return (p);
95 return (0);
96}
97
98/* siefca@pld.org.pl */
99#define MAX_SUBSTITUTION_LEN 32
100#define SV_BEGIN_MARK "$("
101#define SV_END_MARK ")"
102#define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
103#define SV_END_LEN ((sizeof(SV_END_MARK))-1)
104
105/* siefca@pld.org.pl */
106struct var_data {
107 const char *name;
108 const char *value;
109 const size_t size;
110 size_t value_length;
111 } ;
112
113/* siefca@pld.org.pl */
114typedef int (*parsefunc)(const char *, size_t, void *);
115
116/* siefca@pld.org.pl */
117static struct var_data *get_variable (const char *begin, size_t len,
118 struct var_data *vdt)
119{
120struct var_data *vdp;
121
122 if (!begin || !vdt) /* should never happend */
123 {
124 err("get_variable: critical error while "
125 "parsing substitution variable");
126 return NULL;
127 }
128 if (len < 1)
129 {
130 err("get_variable: unknown empty substitution "
131 "variable - aborting");
132 return NULL;
133 }
134 if (len > MAX_SUBSTITUTION_LEN)
135 {
136 err("get_variable: variable name too long "
137 "while parsing substitution. "
138 "name begins with "
139 SV_BEGIN_MARK
140 "%.*s...", MAX_SUBSTITUTION_LEN, begin);
141 return NULL;
142 }
143
144 for (vdp=vdt; vdp->name; vdp++)
145 if (vdp->size == len+1 &&
146 !strncmp(begin, vdp->name, len))
147 {
148 if (!vdp->value)
149 vdp->value = "";
150 if (!vdp->value_length) /* length cache */
151 vdp->value_length = strlen (vdp->value);
152 return vdp;
153 }
154
155 err("get_variable: unknown substitution variable "
156 SV_BEGIN_MARK
157 "%.*s"
158 SV_END_MARK
159 , (int)len, begin);
160
161 return NULL;
162}
163
164/* siefca@pld.org.pl */
165static int ParsePlugin_counter (const char *p, size_t length, void *vp)
166{
167 if (!p || !vp || length < 0)
168 {
169 err("get_variable: bad arguments while counting "
170 "query string");
171 return -1;
172 }
173
174 *((size_t *)vp) += length;
175
176 return 0;
177}
178
179/* siefca@pld.org.pl */
180static int ParsePlugin_builder (const char *p, size_t length, void *vp)
181{
182char **strptr = (char **) vp;
183
184 if (!p || !vp || length < 0)
185 {
186 err("get_variable: bad arguments while building "
187 "query string");
188 return -1;
189 }
190
191 if (!length) return 0;
192 memcpy ((void *) *strptr, (void *) p, length);
193 *strptr += length;
194
195 return 0;
196}
197
198/* siefca@pld.org.pl */
199static int parse_core (const char *source, struct var_data *vdt,
200 parsefunc outfn, void *result)
201{
202size_t v_size = 0,
203 t_size = 0;
204const char *p, *q, *e,
205 *v_begin, *v_end,
206 *t_begin, *t_end;
207struct var_data *v_ptr;
208
209 if (!source)
210 source = "";
211 if (!result)
212 {
213 err("auth_parse: no memory allocated for result "
214 "while parser core was invoked");
215 return -1;
216 }
217 if (!vdt)
218 {
219 err("auth_parse: no substitution table found "
220 "while parser core was invoked");
221 return -1;
222 }
223
224 q = source;
225 while ( (p=strstr(q, SV_BEGIN_MARK)) )
226 {
227 e = strstr (p, SV_END_MARK);
228 if (!e)
229 {
230 err("auth_parse: syntax error in "
231 "substitution "
232 "- no closing symbol found! "
233 "bad variable begins with:"
234 "%.*s...", MAX_SUBSTITUTION_LEN, p);
235 return -1;
236 }
237
238 /*
239 **
240 ** __________sometext$(variable_name)_________
241 ** | | | |
242 ** t_begin' t_end' `v_begin `v_end
243 **
244 */
245
246 v_begin = p+SV_BEGIN_LEN; /* variable field ptr */
247 v_end = e-SV_END_LEN; /* variable field last character */
248 v_size = v_end-v_begin+1;/* variable field length */
249
250 t_begin = q; /* text field ptr */
251 t_end = p-1; /* text field last character */
252 t_size = t_end-t_begin+1;/* text field length */
253
254 /* work on text */
255 if ( (outfn (t_begin, t_size, result)) == -1 )
256 return -1;
257
258 /* work on variable */
259 v_ptr = get_variable (v_begin, v_size, vdt);
260 if (!v_ptr) return -1;
261
262 if ( (outfn (v_ptr->value, v_ptr->value_length, result)) == -1 )
263 return -1;
264
265 q = e + 1;
266 }
267
268 /* work on last part of text if any */
269 if (*q != '\0')
270 if ( (outfn (q, strlen(q), result)) == -1 )
271 return -1;
272
273 return 0;
274}
275
276/* siefca@pld.org.pl */
277static char *parse_string (const char *source, struct var_data *vdt)
278{
279struct var_data *vdp = NULL;
280char *output_buf = NULL,
281 *pass_buf = NULL;
282size_t buf_size = 2;
283
284 if (source == NULL || *source == '\0' ||
285 vdt == NULL || vdt[0].name == NULL)
286 {
287 err("auth_parse: source clause is empty "
288 "- this is critical error");
289 return NULL;
290 }
291
292 /* zero var_data length cache - important! */
293 for (vdp=vdt; vdp->name; vdp++)
294 vdp->value_length = 0;
295
296
297 /* phase 1 - count and validate string */
298 if ( (parse_core (source, vdt, &ParsePlugin_counter, &buf_size)) != 0)
299 return NULL;
300
301 /* phase 2 - allocate memory */
302 output_buf = malloc (buf_size);
303 if (!output_buf)
304 {
305 perror ("malloc");
306 return NULL;
307 }
308 pass_buf = output_buf;
309
310 /* phase 3 - build the output string */
311 if ( (parse_core (source, vdt, &ParsePlugin_builder, &pass_buf)) != 0)
312 {
313 free (output_buf);
314 return NULL;
315 }
316 *pass_buf = '\0';
317
318 return output_buf;
319}
320
321static char *local_part_escaped(const char *username,
322 char *(*escape_func)(const char *, size_t))
323{
324 const char *p=strchr(username, '@');
325 size_t n=p ? p-username:strlen(username);
326
327 return escape_func(username, n);
328}
329
330static char *domain_part_escaped(const char *username,
331 const char *defdomain,
332 char *(*escape_func)(const char *, size_t))
333{
334 const char *p=strchr(username, '@');
335 size_t n;
336
337 if (p)
338 ++p;
339 else
340 p=defdomain;
341
342 n=strlen(p);
343
344 return escape_func(p, n);
345}
346
347static int local_and_domain_part_escaped(char *(*escape_func)(const char *, size_t),
348 const char *username,
349 const char *defdomain,
350 char **local_ret,
351 char **domain_ret)
352{
353 if ((*local_ret=local_part_escaped(username, escape_func)) == NULL)
354 return 0;
355
356 if ((*domain_ret=domain_part_escaped(username, defdomain,
357 escape_func)) == NULL)
358 {
359 free(*local_ret);
360 return 0;
361 }
362
363 return 1;
364}
365
366/* siefca@pld.org.pl */
367char *auth_parse_select_clause (char *(*escape_func)(const char *, size_t),
368 const char *clause, const char *username,
369 const char *defdomain,
370 const char *service)
371{
372 char *str;
373
374 static struct var_data vd[]={
375 {"local_part", NULL, sizeof("local_part"), 0},
376 {"domain", NULL, sizeof("domain"), 0},
377 {"service", NULL, sizeof("service"), 0},
378 {NULL, NULL, 0, 0}};
379
380 char *l_part;
381 char *d_part;
382
383 if (clause == NULL || *clause == '\0' ||
384 !username || *username == '\0')
385 return NULL;
386
387 if (!local_and_domain_part_escaped(escape_func,
388 username, defdomain,
389 &l_part, &d_part))
390 return NULL;
391
392 vd[0].value=l_part;
393 vd[1].value=d_part;
394 vd[2].value = service;
395
396 str=parse_string (clause, vd);
397 free(l_part);
398 free(d_part);
399 return str;
400}
401
402/* siefca@pld.org.pl */
403char *auth_parse_chpass_clause (char *(*escape_func)(const char *, size_t),
404 const char *clause, const char *username,
405 const char *defdomain, const char *newpass,
406 const char *newpass_crypt)
407{
408 char *str;
409
410 static struct var_data vd[]={
411 {"local_part", NULL, sizeof("local_part"), 0},
412 {"domain", NULL, sizeof("domain"), 0},
413 {"newpass", NULL, sizeof("newpass"), 0},
414 {"newpass_crypt", NULL, sizeof("newpass_crypt"), 0},
415 {NULL, NULL, 0, 0}};
416 char *l_part;
417 char *d_part;
418
419 if (clause == NULL || *clause == '\0' ||
420 !username || *username == '\0' ||
421 !newpass || *newpass == '\0' ||
422 !newpass_crypt || *newpass_crypt == '\0') return NULL;
423
424 if (!local_and_domain_part_escaped(escape_func,
425 username, defdomain,
426 &l_part, &d_part))
427 return NULL;
428
429 vd[0].value=l_part;
430 vd[1].value=d_part;
431 vd[2].value = newpass;
432 vd[3].value = newpass_crypt;
433
434 if (!vd[0].value || !vd[1].value ||
435 !vd[2].value || !vd[3].value)
436 {
437 free(l_part);
438 free(d_part);
439 return NULL;
440 }
441
442 str=parse_string (clause, vd);
443 free(l_part);
444 free(d_part);
445 return str;
446}