GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / saslauthd / lak.c
1 /* COPYRIGHT
2  * Copyright (c) 2002-2003 Igor Brezac
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY IGOR BREZAC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IGOR BREZAC OR
18  * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
24  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25  * DAMAGE.
26  * END COPYRIGHT */
27
28 #ifndef AUTH_LDAP
29         #include "mechanisms.h"
30         #include "utils.h"
31 #endif
32
33 #ifdef AUTH_LDAP
34
35 #include <sys/time.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <ctype.h>
41
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45
46 #ifdef HAVE_CRYPT_H
47 #include <crypt.h>
48 #endif
49
50 #ifdef HAVE_OPENSSL
51 #ifndef OPENSSL_DISABLE_OLD_DES_SUPPORT
52 #define OPENSSL_DISABLE_OLD_DES_SUPPORT
53 #endif
54 #include <openssl/evp.h>
55 #include <openssl/des.h>
56 #endif
57
58 #include <ldap.h>
59 #include <lber.h>
60 #include <sasl.h>
61 #include "lak.h"
62
63 typedef struct lak_auth_method {
64         int method;
65         int (*check) (LAK *lak, const char *user, const char *service, const char *realm, const char *password) ;
66 } LAK_AUTH_METHOD;
67
68 typedef struct lak_hash_rock {
69         const char *mda;
70         int salted;
71 } LAK_HASH_ROCK;
72
73 typedef struct lak_password_scheme {
74         char *hash;
75         int (*check) (const char *cred, const char *passwd, void *rock);
76         void *rock;
77 } LAK_PASSWORD_SCHEME;
78
79 static int lak_config_read(LAK_CONF *, const char *);
80 static int lak_config_int(const char *);
81 static int lak_config_switch(const char *);
82 static void lak_config_free(LAK_CONF *);
83 static int lak_config(const char *, LAK_CONF **);
84 static int lak_escape(const char *, const unsigned int, char **);
85 static int lak_tokenize_domains(const char *, int, char **);
86 static int lak_expand_tokens(const char *, const char *, const char *, const char *, const char *, char **);
87 static int lak_connect(LAK *);
88 static int lak_bind(LAK *, LAK_USER *);
89 static void lak_unbind(LAK *);
90 static int lak_auth_custom(LAK *, const char *, const char *, const char *, const char *);
91 static int lak_auth_bind(LAK *, const char *, const char *, const char *, const char *);
92 static int lak_auth_fastbind(LAK *, const char *, const char *, const char *, const char *);
93 static int lak_group_member(LAK *, const char *, const char *, const char *, const char *);
94 static char *lak_result_get(const LAK_RESULT *, const char *);
95 static int lak_result_add(const char *, const char *, LAK_RESULT **);
96 static int lak_check_password(const char *, const char *, void *);
97 static int lak_check_crypt(const char *, const char *, void *);
98 #ifdef HAVE_OPENSSL
99 static int lak_base64_decode(const char *, char **, int *);
100 static int lak_check_hashed(const char *, const char *, void *);
101 #endif
102 static int lak_sasl_interact(LDAP *, unsigned, void *, void *);
103 static int lak_user(const char *, const char *, const char *, const char *, const char *, const char *, LAK_USER **);
104 static int lak_user_copy(LAK_USER **, const LAK_USER *);
105 static int lak_user_cmp(const LAK_USER *, const LAK_USER *);
106 static void lak_user_free(LAK_USER *);
107
108 static LAK_AUTH_METHOD authenticator[] = {
109         { LAK_AUTH_METHOD_BIND, lak_auth_bind },
110         { LAK_AUTH_METHOD_CUSTOM, lak_auth_custom },
111         { LAK_AUTH_METHOD_FASTBIND, lak_auth_fastbind },
112         { -1, NULL }
113 };
114
115 static LAK_HASH_ROCK hash_rock[] = {
116         { "md5", 0 },
117         { "md5", 1 },
118         { "sha1", 0 },
119         { "sha1", 1 }
120 };
121
122 static LAK_PASSWORD_SCHEME password_scheme[] = {
123         { "{CRYPT}", lak_check_crypt, NULL },
124         { "{UNIX}", lak_check_crypt, NULL },
125 #ifdef HAVE_OPENSSL
126         { "{MD5}", lak_check_hashed, &hash_rock[0] },
127         { "{SMD5}", lak_check_hashed, &hash_rock[1] },
128         { "{SHA}", lak_check_hashed, &hash_rock[2] },
129         { "{SSHA}", lak_check_hashed, &hash_rock[3] },
130 #endif
131         { NULL, NULL, NULL }
132 };
133
134 static const char *dn_attr = "dn";
135
136 #define ISSET(x)  ((x != NULL) && (*(x) != '\0'))
137 #define EMPTY(x)  ((x == NULL) || (*(x) == '\0'))
138
139 static int lak_config_read(
140         LAK_CONF *conf,
141         const char *configfile)
142 {
143         FILE *infile;
144         int lineno = 0;
145         char buf[4096];
146         char *p, *key;
147
148         infile = fopen(configfile, "r");
149         if (!infile) {
150             syslog(LOG_ERR|LOG_AUTH,
151                    "Could not open saslauthd config file: %s (%m)",
152                    configfile);
153             return LAK_FAIL;
154         }
155     
156         while (fgets(buf, sizeof(buf), infile)) {
157                 lineno++;
158
159                 if (buf[strlen(buf)-1] == '\n') 
160                         buf[strlen(buf)-1] = '\0';
161                 for (p = buf; *p && isspace((int) *p); p++);
162                         if (!*p || *p == '#') 
163                                 continue;
164
165                 key = p;
166                 while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
167                         if (isupper((int) *p)) 
168                                 *p = tolower(*p);
169                         p++;
170                 }
171                 if (*p != ':')
172                         return LAK_FAIL;
173                 
174                 *p++ = '\0';
175
176                 while (*p && isspace((int) *p)) 
177                         p++;
178
179                 if (!*p)
180                         return LAK_FAIL;
181
182                 if (!strcasecmp(key, "ldap_servers"))
183                         strlcpy(conf->servers, p, LAK_URL_LEN);
184
185                 else if (!strcasecmp(key, "ldap_bind_dn"))
186                         strlcpy(conf->bind_dn, p, LAK_DN_LEN);
187
188                 else if (!strcasecmp(key, "ldap_bind_pw") ||
189                          !strcasecmp(key, "ldap_password"))
190                         strlcpy(conf->password, p, LAK_BUF_LEN);
191
192                 else if (!strcasecmp(key, "ldap_version"))
193                         conf->version = lak_config_int(p);
194
195                 else if (!strcasecmp(key, "ldap_search_base"))
196                         strlcpy(conf->search_base, p, LAK_DN_LEN);
197
198                 else if (!strcasecmp(key, "ldap_filter"))
199                         strlcpy(conf->filter, p, LAK_DN_LEN);
200                 
201                 else if (!strcasecmp(key, "ldap_password_attr"))
202                         strlcpy(conf->password_attr, p, LAK_BUF_LEN);
203
204                 else if (!strcasecmp(key, "ldap_group_dn"))
205                         strlcpy(conf->group_dn, p, LAK_DN_LEN);
206                 
207                 else if (!strcasecmp(key, "ldap_group_attr"))
208                         strlcpy(conf->group_attr, p, LAK_BUF_LEN);
209
210                 else if (!strcasecmp(key, "ldap_group_filter"))
211                         strlcpy(conf->group_filter, p, LAK_BUF_LEN);
212
213                 else if (!strcasecmp(key, "ldap_group_search_base"))
214                         strlcpy(conf->group_search_base, p, LAK_BUF_LEN);
215
216                 else if (!strcasecmp(key, "ldap_group_scope")) {
217                         if (!strcasecmp(p, "one")) {
218                                 conf->group_scope = LDAP_SCOPE_ONELEVEL;
219                         } else if (!strcasecmp(p, "base")) {
220                                 conf->group_scope = LDAP_SCOPE_BASE;
221                         }
222                 } else if (!strcasecmp(key, "ldap_group_match_method")) {
223                         if (!strcasecmp(p, "filter")) {
224                                 conf->group_match_method = LAK_GROUP_MATCH_METHOD_FILTER;
225                         } else if (!strcasecmp(p, "attr")) {
226                                 conf->group_match_method = LAK_GROUP_MATCH_METHOD_ATTR;
227                         }
228                 } else if (!strcasecmp(key, "ldap_default_realm") ||
229                          !strcasecmp(key, "ldap_default_domain"))
230                         strlcpy(conf->default_realm, p, LAK_BUF_LEN);
231
232                 else if (!strcasecmp(key, "ldap_auth_method")) {
233                         if (!strcasecmp(p, "custom")) {
234                                 conf->auth_method = LAK_AUTH_METHOD_CUSTOM;
235                         } else if (!strcasecmp(p, "fastbind")) {
236                                 conf->auth_method = LAK_AUTH_METHOD_FASTBIND;
237                         }
238                 } else if (!strcasecmp(key, "ldap_timeout")) {
239                         conf->timeout.tv_sec = lak_config_int(p);
240                         conf->timeout.tv_usec = 0;
241                 } else if (!strcasecmp(key, "ldap_size_limit"))
242                         conf->size_limit = lak_config_int(p);
243
244                 else if (!strcasecmp(key, "ldap_time_limit"))
245                         conf->time_limit = lak_config_int(p);
246
247                 else if (!strcasecmp(key, "ldap_deref")) {
248                         if (!strcasecmp(p, "search")) {
249                                 conf->deref = LDAP_DEREF_SEARCHING;
250                         } else if (!strcasecmp(p, "find")) {
251                                 conf->deref = LDAP_DEREF_FINDING;
252                         } else if (!strcasecmp(p, "always")) {
253                                 conf->deref = LDAP_DEREF_ALWAYS;
254                         } else if (!strcasecmp(p, "never")) {
255                                 conf->deref = LDAP_DEREF_NEVER;
256                         }
257                 } else if (!strcasecmp(key, "ldap_referrals")) {
258                         conf->referrals = lak_config_switch(p);
259
260                 } else if (!strcasecmp(key, "ldap_restart")) {
261                         conf->restart = lak_config_switch(p);
262
263                 } else if (!strcasecmp(key, "ldap_scope")) {
264                         if (!strcasecmp(p, "one")) {
265                                 conf->scope = LDAP_SCOPE_ONELEVEL;
266                         } else if (!strcasecmp(p, "base")) {
267                                 conf->scope = LDAP_SCOPE_BASE;
268                         }
269                 } else if (!strcasecmp(key, "ldap_use_sasl")) {
270                         conf->use_sasl = lak_config_switch(p);
271
272                 } else if (!strcasecmp(key, "ldap_id") ||
273                    !strcasecmp(key, "ldap_sasl_authc_id"))
274                         strlcpy(conf->id, p, LAK_BUF_LEN);
275
276                 else if (!strcasecmp(key, "ldap_authz_id") ||
277                  !strcasecmp(key, "ldap_sasl_authz_id"))
278                         strlcpy(conf->authz_id, p, LAK_BUF_LEN);
279
280                 else if (!strcasecmp(key, "ldap_realm") ||
281                  !strcasecmp(key, "ldap_sasl_realm"))
282                         strlcpy(conf->realm, p, LAK_BUF_LEN);
283
284                 else if (!strcasecmp(key, "ldap_mech") ||
285                  !strcasecmp(key, "ldap_sasl_mech"))
286                         strlcpy(conf->mech, p, LAK_BUF_LEN);
287
288                 else if (!strcasecmp(key, "ldap_sasl_secprops"))
289                         strlcpy(conf->sasl_secprops, p, LAK_BUF_LEN);
290
291                 else if (!strcasecmp(key, "ldap_start_tls"))
292                         conf->start_tls = lak_config_switch(p);
293
294                 else if (!strcasecmp(key, "ldap_tls_check_peer"))
295                         conf->tls_check_peer = lak_config_switch(p);
296
297                 else if (!strcasecmp(key, "ldap_tls_cacert_file"))
298                         strlcpy(conf->tls_cacert_file, p, LAK_PATH_LEN);
299
300                 else if (!strcasecmp(key, "ldap_tls_cacert_dir"))
301                         strlcpy(conf->tls_cacert_dir, p, LAK_PATH_LEN);
302
303                 else if (!strcasecmp(key, "ldap_tls_ciphers"))
304                         strlcpy(conf->tls_ciphers, p, LAK_BUF_LEN);
305
306                 else if (!strcasecmp(key, "ldap_tls_cert"))
307                         strlcpy(conf->tls_cert, p, LAK_PATH_LEN);
308
309                 else if (!strcasecmp(key, "ldap_tls_key"))
310                         strlcpy(conf->tls_key, p, LAK_PATH_LEN);
311
312                 else if (!strcasecmp(key, "ldap_debug"))
313                         conf->debug = lak_config_int(p);
314         }
315
316         if (conf->version != LDAP_VERSION3 && 
317             (conf->use_sasl ||
318              conf->start_tls))
319             conf->version = LDAP_VERSION3;
320
321     if (conf->use_sasl &&
322         conf->auth_method == LAK_AUTH_METHOD_BIND)
323         conf->auth_method = LAK_AUTH_METHOD_FASTBIND;
324
325     if ( ISSET(conf->group_filter) &&
326          ISSET(conf->search_base) &&
327          EMPTY(conf->group_search_base) )
328         strlcpy(conf->group_search_base, conf->search_base, LAK_DN_LEN);
329         
330         fclose(infile);
331
332         return LAK_OK;
333 }
334
335 static int lak_config_int(
336         const char *val)
337 {
338     if (!val) return 0;
339
340     if (!isdigit((int) *val) && (*val != '-' || !isdigit((int) val[1]))) return 0;
341
342     return atoi(val);
343 }
344
345 static int lak_config_switch(
346         const char *val)
347 {
348     if (!val) return 0;
349     
350     if (*val == '0' || *val == 'n' ||
351         (*val == 'o' && val[1] == 'f') || *val == 'f') {
352         return 0;
353     } else if (*val == '1' || *val == 'y' ||
354              (*val == 'o' && val[1] == 'n') || *val == 't') {
355         return 1;
356     }
357     return 0;
358 }
359
360 static int lak_config(
361         const char *configfile, 
362         LAK_CONF **ret)
363 {
364         LAK_CONF *conf;
365         int rc = 0;
366
367         conf = malloc( sizeof(LAK_CONF) );
368         if (conf == NULL) {
369                 return LAK_NOMEM;
370         }
371
372         memset(conf, 0, sizeof(LAK_CONF));
373
374         strlcpy(conf->servers, "ldap://localhost/", LAK_BUF_LEN);
375         conf->version = LDAP_VERSION3;
376         strlcpy(conf->filter, "(uid=%u)", LAK_DN_LEN);
377         strlcpy(conf->password_attr, "userPassword", LAK_BUF_LEN);
378         conf->scope = LDAP_SCOPE_SUBTREE;
379         strlcpy(conf->group_attr, "uniqueMember", LAK_BUF_LEN);
380         conf->group_scope = LDAP_SCOPE_SUBTREE;
381     conf->group_match_method = LAK_GROUP_MATCH_METHOD_ATTR;
382         conf->auth_method = LAK_AUTH_METHOD_BIND;
383         conf->timeout.tv_sec = 5;
384         conf->timeout.tv_usec = 0;
385         conf->size_limit = 1;
386         conf->time_limit = 5;
387         conf->deref = LDAP_DEREF_NEVER;
388         conf->restart = 1;
389         conf->start_tls = 0;
390         conf->use_sasl = 0;
391
392         strlcpy(conf->path, configfile, LAK_PATH_LEN);
393
394         rc = lak_config_read(conf, conf->path);
395         if (rc != LAK_OK) {
396                 lak_config_free(conf);
397                 return rc;
398         }
399
400         *ret = conf;
401         return LAK_OK;
402 }
403
404 static void lak_config_free(
405         LAK_CONF *conf) 
406 {
407         if (conf == NULL) {
408                 return;
409         }
410
411         memset(conf, 0, sizeof(LAK_CONF));
412
413         free (conf);
414
415         return;
416 }
417
418 /*
419  * Note: calling function must free memory.
420  */
421 static int lak_escape(
422         const char *s, 
423         const unsigned int n, 
424         char **result) 
425 {
426         char *buf;
427         char *end, *ptr, *temp;
428
429         if (n > strlen(s))  // Sanity check, just in case
430                 return LAK_FAIL;
431
432         buf = malloc(n * 5 + 1);
433         if (buf == NULL) {
434                 return LAK_NOMEM;
435         }
436
437         buf[0] = '\0';
438         ptr = (char *)s;
439         end = ptr + n;
440
441         while (((temp = strpbrk(ptr, "*()\\\0"))!=NULL) && (temp<end)) {
442
443                 if (temp>ptr)
444                         strncat(buf, ptr, temp-ptr);
445
446                 switch (*temp) {
447                         case '*':
448                                 strcat(buf, "\\2a");
449                                 break;
450                         case '(':
451                                 strcat(buf, "\\28");
452                                 break;
453                         case ')':
454                                 strcat(buf, "\\29");
455                                 break;
456                         case '\\':
457                                 strcat(buf, "\\5c");
458                                 break;
459                         case '\0':
460                                 strcat(buf, "\\00");
461                                 break;
462                 }
463                 ptr=temp+1;
464         }
465         if (ptr<end)
466                 strncat(buf, ptr, end-ptr);
467
468         *result = buf;
469
470         return LAK_OK;
471 }
472
473 static int lak_tokenize_domains(
474         const char *d, 
475         int n, 
476         char **result)
477 {
478         char *s, *s1;
479         char *lasts;
480         int nt, i, rc;
481
482         *result = NULL;
483
484         if (d == NULL || n < 1 || n > 9)
485                 return LAK_FAIL;
486
487         s = strdup(d);
488         if (s == NULL)
489                 return LAK_NOMEM;
490
491         for( nt=0, s1=s; *s1; s1++ )
492                 if( *s1 == '.' ) nt++;
493         nt++;
494
495         if (n > nt) {
496                 free(s);
497                 return LAK_FAIL;
498         }
499
500         i = nt - n;
501         s1 = (char *)strtok_r(s, ".", &lasts);
502         while(s1) {
503                 if (i == 0) {
504                         rc = lak_escape(s1, strlen(s1), result);
505                         free(s);
506                         return rc;
507                 }
508                 s1 = (char *)strtok_r(NULL, ".", &lasts);
509                 i--;
510         }
511
512         free(s);
513         return LAK_FAIL;
514 }
515
516 #define LAK_MAX(a,b) (a>b?a:b)
517
518 /*
519  * lak_expand_tokens
520  * Parts with the strings provided.
521  *   %%   = %
522  *   %u   = user
523  *   %U   = user part of %u
524  *   %d   = domain part of %u if available, othwise same as %r
525  *   %1-9 = domain if not available realm, token
526  *          (%1 = tld, %2 = domain when %r = domain.tld)
527  *   %s   = service
528  *   %r   = realm
529  *   %R   = prepend '@' to realm
530  *   %D   = user DN
531  * Note: calling function must free memory.
532  */
533 static int lak_expand_tokens(
534         const char *pattern,
535         const char *username, 
536         const char *service,
537         const char *realm,
538         const char *dn,
539         char **result) 
540 {
541         char *buf; 
542         char *end, *ptr, *temp;
543         char *ebuf, *user;
544         char *domain;
545         int rc;
546
547         /* to permit multiple occurences of username and/or realm in filter */
548         /* and avoid memory overflow in filter build [eg: (|(uid=%u)(userid=%u)) ] */
549         int percents, service_len, realm_len, dn_len, user_len, maxparamlength;
550         
551         if (pattern == NULL) {
552                 syslog(LOG_ERR|LOG_AUTH, "filter pattern not setup");
553                 return LAK_FAIL;
554         }
555
556         /* find the longest param of username and realm, 
557            do not worry about domain because it is always shorter 
558            then username                                           */
559         user_len=ISSET(username) ? strlen(username) : 0;
560         service_len=ISSET(service) ? strlen(service) : 0;
561         realm_len=ISSET(realm) ? strlen(realm) : 0;
562         dn_len=ISSET(dn) ? strlen(dn) : 0;
563
564         maxparamlength = LAK_MAX(user_len, service_len);
565         maxparamlength = LAK_MAX(maxparamlength, realm_len + 1);  /* +1 for %R when '@' is prepended */
566         maxparamlength = LAK_MAX(maxparamlength, dn_len);
567
568         /* find the number of occurences of percent sign in filter */
569         for( percents=0, buf=(char *)pattern; *buf; buf++ ) {
570                 if( *buf == '%' ) percents++;
571         }
572
573         /* percents * 3 * maxparamlength because we need to account for
574          * an entirely-escaped worst-case-length parameter */
575         buf=malloc(strlen(pattern) + (percents * 3 * maxparamlength) + 1);
576         if(buf == NULL)
577                 return LAK_NOMEM;
578         buf[0] = '\0';
579         
580         ptr = (char *)pattern;
581         end = ptr + strlen(ptr);
582
583         while ((temp=strchr(ptr,'%'))!=NULL ) {
584
585                 if ((temp-ptr) > 0)
586                         strncat(buf, ptr, temp-ptr);
587
588                 if ((temp+1) >= end) {
589                         syslog(LOG_DEBUG|LOG_AUTH, "Incomplete lookup substitution format");
590                         break;
591                 }
592
593                 switch (*(temp+1)) {
594                         case '%':
595                                 strncat(buf,temp+1,1);
596                                 break;
597                         case 'u':
598                                 if (ISSET(username)) {
599                                         rc=lak_escape(username, strlen(username), &ebuf);
600                                         if (rc == LAK_OK) {
601                                                 strcat(buf,ebuf);
602                                                 free(ebuf);
603                                         }
604                                 } else
605                                         syslog(LOG_DEBUG|LOG_AUTH, "Username not available.");
606                                 break;
607                         case 'U':
608                                 if (ISSET(username)) {
609                                         user = strchr(username, '@');
610                                         rc=lak_escape(username, (user ? user - username : strlen(username)), &ebuf);
611                                         if (rc == LAK_OK) {
612                                                 strcat(buf,ebuf);
613                                                 free(ebuf);
614                                         }
615                                 } else
616                                         syslog(LOG_DEBUG|LOG_AUTH, "Username not available.");
617                                 break;
618                         case '1':
619                         case '2':
620                         case '3':
621                         case '4':
622                         case '5':
623                         case '6':
624                         case '7':
625                         case '8':
626                         case '9':
627                                 if (ISSET(username) && 
628                                     ((domain = strchr(username, '@')) && domain[1]!='\0')) {
629                                         rc=lak_tokenize_domains(domain+1, (int) *(temp+1)-48, &ebuf);
630                                         if (rc == LAK_OK) {
631                                                 strcat(buf,ebuf);
632                                                 free(ebuf);
633                                         }
634                                 } else if (ISSET(realm)) {
635                                         rc=lak_tokenize_domains(realm, (int) *(temp+1)-48, &ebuf);
636                                         if (rc == LAK_OK) {
637                                                 strcat(buf,ebuf);
638                                                 free(ebuf);
639                                         }
640                                 } else
641                                         syslog(LOG_DEBUG|LOG_AUTH, "Domain/Realm not available.");
642                                 break;
643                         case 'd':
644                                 if (ISSET(username) && 
645                                     ((domain = strchr(username, '@')) && domain[1]!='\0')) {
646                                         rc=lak_escape(domain+1, strlen(domain+1), &ebuf);
647                                         if (rc == LAK_OK) {
648                                                 strcat(buf,ebuf);
649                                                 free(ebuf);
650                                         }
651                                         break;
652                                 } 
653                         case 'R':
654                         case 'r':
655                                 if (ISSET(realm)) {
656                                         rc = lak_escape(realm, strlen(realm), &ebuf);
657                                         if (rc == LAK_OK) {
658                                                 if (*(temp+1) == 'R')
659                                                         strcat(buf,"@");
660                                                 strcat(buf,ebuf);
661                                                 free(ebuf);
662                                         }
663                                 } else
664                                         syslog(LOG_DEBUG|LOG_AUTH, "Domain/Realm not available.");
665                                 break;
666                         case 's':
667                                 if (ISSET(service)) {
668                                         rc = lak_escape(service, strlen(service), &ebuf);
669                                         if (rc == LAK_OK) {
670                                                 strcat(buf,ebuf);
671                                                 free(ebuf);
672                                         }
673                                 } else
674                                         syslog(LOG_DEBUG|LOG_AUTH, "Service not available.");
675                                 break;
676                         case 'D':
677                                 if (ISSET(dn)) {
678                                         rc = lak_escape(dn, strlen(dn), &ebuf);
679                                         if (rc == LAK_OK) {
680                                                 strcat(buf,ebuf);
681                                                 free(ebuf);
682                                         }
683                                 } else
684                                         syslog(LOG_DEBUG|LOG_AUTH, "User DN not available.");
685                                 break;
686                         default:
687                                 break;
688                 }
689                 ptr=temp+2;
690         }
691         if (temp<end)
692                 strcat(buf, ptr);
693
694         *result = buf;
695
696         return LAK_OK;
697 }
698
699 int lak_init(
700         const char *configfile, 
701         LAK **ret) 
702 {
703         LAK *lak;
704         int rc;
705
706         lak = *ret;
707
708         if (lak != NULL) {
709                 return LAK_OK;
710         }
711
712         lak = (LAK *)malloc(sizeof(LAK));
713         if (lak == NULL)
714                 return LAK_NOMEM;
715
716         lak->status=LAK_NOT_BOUND;
717         lak->ld=NULL;
718         lak->conf=NULL;
719         lak->user=NULL;
720
721         rc = lak_config(configfile, &lak->conf);
722         if (rc != LAK_OK) {
723                 free(lak);
724                 return rc;
725         }
726
727 #ifdef HAVE_OPENSSL
728         OpenSSL_add_all_digests();
729 #endif
730
731         *ret=lak;
732         return LAK_OK;
733 }
734
735 void lak_close(
736         LAK *lak) 
737 {
738
739         if (lak == NULL)
740                 return;
741
742         lak_config_free(lak->conf);
743
744         lak_unbind(lak);
745
746         free(lak);
747
748 #ifdef HAVE_OPENSSL
749         EVP_cleanup();
750 #endif
751
752         return;
753 }
754
755 static int lak_connect(
756         LAK *lak)
757 {
758         int rc = 0;
759         char *p = NULL;
760
761         if (ISSET(lak->conf->tls_cacert_file)) {
762                 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, lak->conf->tls_cacert_file);
763                 if (rc != LDAP_SUCCESS) {
764                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CACERTFILE (%s).", ldap_err2string (rc));
765                 }
766         }
767
768         if (ISSET(lak->conf->tls_cacert_dir)) {
769                 rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, lak->conf->tls_cacert_dir);
770                 if (rc != LDAP_SUCCESS) {
771                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CACERTDIR (%s).", ldap_err2string (rc));
772                 }
773         }
774
775         if (lak->conf->tls_check_peer != 0) {
776                 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &lak->conf->tls_check_peer);
777                 if (rc != LDAP_SUCCESS) {
778                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_REQUIRE_CERT (%s).", ldap_err2string (rc));
779                 }
780         }
781
782         if (ISSET(lak->conf->tls_ciphers)) {
783                 /* set cipher suite, certificate and private key: */
784                 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, lak->conf->tls_ciphers);
785                 if (rc != LDAP_SUCCESS) {
786                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CIPHER_SUITE (%s).", ldap_err2string (rc));
787                 }
788         }
789
790         if (ISSET(lak->conf->tls_cert)) {
791                 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, lak->conf->tls_cert);
792                 if (rc != LDAP_SUCCESS) {
793                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CERTFILE (%s).", ldap_err2string (rc));
794                 }
795         }
796
797         if (ISSET(lak->conf->tls_key)) {
798                 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, lak->conf->tls_key);
799                 if (rc != LDAP_SUCCESS) {
800                         syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_KEYFILE (%s).", ldap_err2string (rc));
801                 }
802         }
803
804         rc = ldap_initialize(&lak->ld, lak->conf->servers);
805         if (rc != LDAP_SUCCESS) {
806                 syslog(LOG_ERR|LOG_AUTH, "ldap_initialize failed (%s)", lak->conf->servers);
807                 return LAK_CONNECT_FAIL;
808         }
809
810         if (lak->conf->debug) {
811                 rc = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(lak->conf->debug));
812                 if (rc != LDAP_OPT_SUCCESS)
813                         syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_DEBUG_LEVEL %x.", lak->conf->debug);
814         }
815
816         rc = ldap_set_option(lak->ld, LDAP_OPT_PROTOCOL_VERSION, &(lak->conf->version));
817         if (rc != LDAP_OPT_SUCCESS) {
818
819                 if (lak->conf->use_sasl ||
820                     lak->conf->start_tls) {
821                         syslog(LOG_ERR|LOG_AUTH, "Failed to set LDAP_OPT_PROTOCOL_VERSION %d, required for ldap_start_tls and ldap_use_sasl.", lak->conf->version);
822                         lak_unbind(lak);
823                         return LAK_CONNECT_FAIL;
824                 } else
825                         syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_PROTOCOL_VERSION %d.", lak->conf->version);
826
827                 lak->conf->version = LDAP_VERSION2;
828
829         }
830
831         rc = ldap_set_option(lak->ld, LDAP_OPT_NETWORK_TIMEOUT, &(lak->conf->timeout));
832         if (rc != LDAP_OPT_SUCCESS) {
833                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_NETWORK_TIMEOUT %d.%d.", lak->conf->timeout.tv_sec, lak->conf->timeout.tv_usec);
834         }
835
836         rc = ldap_set_option(lak->ld, LDAP_OPT_TIMELIMIT, &(lak->conf->time_limit));
837         if (rc != LDAP_OPT_SUCCESS) {
838                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_TIMELIMIT %d.", lak->conf->time_limit);
839         }
840
841         rc = ldap_set_option(lak->ld, LDAP_OPT_DEREF, &(lak->conf->deref));
842         if (rc != LDAP_OPT_SUCCESS) {
843                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_DEREF %d.", lak->conf->deref);
844         }
845
846         rc = ldap_set_option(lak->ld, LDAP_OPT_REFERRALS, lak->conf->referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
847         if (rc != LDAP_OPT_SUCCESS) {
848                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_REFERRALS.");
849         }
850
851         rc = ldap_set_option(lak->ld, LDAP_OPT_SIZELIMIT, &(lak->conf->size_limit));
852         if (rc != LDAP_OPT_SUCCESS)
853                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_SIZELIMIT %d.", lak->conf->size_limit);
854
855         rc = ldap_set_option(lak->ld, LDAP_OPT_RESTART, lak->conf->restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
856         if (rc != LDAP_OPT_SUCCESS) {
857                 syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_RESTART.");
858         }
859
860         if (lak->conf->start_tls) {
861
862                 rc = ldap_start_tls_s(lak->ld, NULL, NULL);
863                 if (rc != LDAP_SUCCESS) {
864                         syslog(LOG_ERR|LOG_AUTH, "start tls failed (%s).", ldap_err2string(rc));
865                         lak_unbind(lak);
866                         return LAK_CONNECT_FAIL;
867                 }
868         }
869         
870         if (lak->conf->use_sasl) {
871
872                 if (EMPTY(lak->conf->mech)) {
873                         ldap_get_option(lak->ld, LDAP_OPT_X_SASL_MECH, &p);
874                         if (p)
875                                 strlcpy(lak->conf->mech, p, LAK_BUF_LEN);
876                 }
877
878                 if (EMPTY(lak->conf->realm)) {
879                         ldap_get_option(lak->ld, LDAP_OPT_X_SASL_REALM, &p);
880                         if (p)
881                                 strlcpy(lak->conf->realm, p, LAK_BUF_LEN);
882                 }
883
884                 if (ISSET(lak->conf->sasl_secprops)) {
885                         rc = ldap_set_option(lak->ld, LDAP_OPT_X_SASL_SECPROPS, (void *) lak->conf->sasl_secprops);
886                         if( rc != LDAP_OPT_SUCCESS ) {
887                                 syslog(LOG_ERR|LOG_AUTH, "Unable to set LDAP_OPT_X_SASL_SECPROPS.");
888                                 lak_unbind(lak);
889                                 return LAK_CONNECT_FAIL;
890                         }
891                 }
892         }
893
894
895         return LAK_OK;
896 }
897
898 static int lak_user(
899         const char *bind_dn, 
900         const char *id, 
901         const char *authz_id, 
902         const char *mech, 
903         const char *realm, 
904         const char *password, 
905         LAK_USER **ret)
906 {
907         LAK_USER *lu = NULL;
908         
909         *ret = NULL;
910
911         lu = (LAK_USER *)malloc(sizeof(LAK_USER));
912         if (lu == NULL)
913                 return LAK_NOMEM;
914
915         memset(lu, 0, sizeof(LAK_USER));
916
917         if (ISSET(bind_dn))
918                 strlcpy(lu->bind_dn, bind_dn, LAK_DN_LEN);
919
920         if (ISSET(id))
921                 strlcpy(lu->id, id, LAK_BUF_LEN);
922
923         if (ISSET(authz_id))
924                 strlcpy(lu->authz_id, authz_id, LAK_BUF_LEN);
925
926         if (ISSET(mech))
927                 strlcpy(lu->mech, mech, LAK_BUF_LEN);
928
929         if (ISSET(realm))
930                 strlcpy(lu->realm, realm, LAK_BUF_LEN);
931
932         if (ISSET(password))
933                 strlcpy(lu->password, password, LAK_BUF_LEN);
934         
935         *ret = lu;
936         return LAK_OK;
937 }
938
939 static int lak_user_cmp(
940         const LAK_USER *lu1,
941         const LAK_USER *lu2)
942 {
943
944         if (lu1 == NULL ||
945             lu2 == NULL)
946                 return LAK_FAIL;
947         
948         if (memcmp(lu1, lu2, sizeof(LAK_USER)) == 0)
949                 return LAK_OK;
950
951         return LAK_FAIL;
952 }
953
954 static int lak_user_copy(
955         LAK_USER **lu1,
956         const LAK_USER *lu2)
957 {
958         LAK_USER *lu;
959
960         lu = *lu1;
961
962         if (lu2 == NULL)
963                 return LAK_FAIL;
964
965         if (lu == NULL) {
966                 lu = (LAK_USER *)malloc(sizeof(LAK_USER));
967                 if (lu == NULL)
968                         return LAK_NOMEM;
969                 
970                 *lu1 = lu;
971         }
972
973         memcpy((void *)lu, (void *)lu2, sizeof(LAK_USER));
974
975         return LAK_OK;
976 }
977
978 static void lak_user_free(
979         LAK_USER *user)
980 {
981         if (user == NULL) {
982                 return;
983         }
984
985         memset(user, 0, sizeof(LAK_USER));
986
987         free(user);
988
989         return;
990 }
991
992 static int lak_sasl_interact(
993         LDAP *ld, 
994         unsigned flags __attribute__((unused)), 
995         void *def, 
996         void *inter)
997 {
998         sasl_interact_t *in = inter;
999         const char *p;
1000         LAK_USER *lu = def;
1001
1002         for (;in->id != SASL_CB_LIST_END;in++) {
1003                 p = NULL;
1004                 switch(in->id) {
1005                         case SASL_CB_AUTHNAME:
1006                                 if (ISSET(lu->id))
1007                                         p = lu->id;
1008                                 if (!p)
1009                                         ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &p);
1010                                 break;
1011                         case SASL_CB_USER:
1012                                 if (ISSET(lu->authz_id))
1013                                         p = lu->authz_id;
1014                                 if (!p)
1015                                         ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &p);
1016                                 break;
1017                         case SASL_CB_GETREALM:
1018                                 if (ISSET(lu->realm))
1019                                         p = lu->realm;
1020                                 break;          
1021                         case SASL_CB_PASS:
1022                                 if (ISSET(lu->password))
1023                                         p = lu->password;
1024                                 break;
1025                 }
1026
1027                 in->result = ISSET(p) ? p : "";
1028                 in->len = strlen(in->result);
1029         }
1030
1031         return LDAP_SUCCESS;
1032 }
1033
1034 static int lak_bind(
1035         LAK *lak, 
1036         LAK_USER *user)
1037 {
1038         int rc;
1039
1040         if (user == NULL)  // Sanity Check
1041                 return LAK_FAIL;
1042
1043         if ((lak->status == LAK_BOUND) &&
1044             (lak_user_cmp(lak->user, user) == LAK_OK))
1045                 return LAK_OK;
1046
1047         lak_user_free(lak->user);
1048         lak->user = NULL;
1049
1050         if (
1051 #if LDAP_VENDOR_VERSION < 20204
1052         lak->conf->use_sasl ||
1053 #endif
1054             lak->conf->version == LDAP_VERSION2) 
1055                 lak->status = LAK_NOT_BOUND;
1056
1057         if (lak->status == LAK_NOT_BOUND) {
1058                 lak_unbind(lak);
1059                 rc = lak_connect(lak);
1060                 if (rc != LAK_OK)
1061                         return rc;
1062         }
1063
1064         if (lak->conf->use_sasl)
1065                 rc = ldap_sasl_interactive_bind_s(
1066                         lak->ld, 
1067                         user->bind_dn,
1068                         user->mech, 
1069                         NULL, 
1070                         NULL, 
1071                         LDAP_SASL_QUIET, 
1072                         lak_sasl_interact, 
1073                         user);
1074         else
1075                 rc = ldap_simple_bind_s(lak->ld, user->bind_dn, user->password);
1076
1077         switch (rc) {
1078                 case LDAP_SUCCESS:
1079                         break;
1080         case LDAP_INVALID_CREDENTIALS:
1081         case LDAP_INSUFFICIENT_ACCESS:
1082         case LDAP_INVALID_DN_SYNTAX:
1083         case LDAP_OTHER: 
1084                         lak->status = LAK_NOT_BOUND;
1085             return LAK_BIND_FAIL;
1086                 case LDAP_TIMEOUT:
1087                 case LDAP_SERVER_DOWN:
1088                 default:
1089                         syslog(LOG_DEBUG|LOG_AUTH,
1090                                    (lak->conf->use_sasl ? "ldap_sasl_interactive_bind() failed %d (%s)." : "ldap_simple_bind() failed %d (%s)."), rc, ldap_err2string(rc));
1091                         lak->status = LAK_NOT_BOUND;
1092                         return LAK_RETRY;
1093         }
1094
1095         rc = lak_user_copy(&(lak->user), user);
1096         if (rc != LAK_OK)
1097                 return rc;
1098
1099         lak->status = LAK_BOUND;
1100
1101         return LAK_OK;
1102 }
1103
1104 static void lak_unbind(
1105         LAK *lak)
1106 {
1107         if (!lak)
1108                 return;
1109
1110         lak_user_free(lak->user);
1111
1112         if (lak->ld)
1113                 ldap_unbind(lak->ld);
1114
1115         lak->ld = NULL;
1116         lak->user = NULL;
1117         lak->status = LAK_NOT_BOUND;
1118
1119         return;
1120 }
1121
1122 /* 
1123  * lak_retrieve - retrieve user@realm values specified by 'attrs'
1124  */
1125 int lak_retrieve(
1126         LAK *lak, 
1127         const char *user, 
1128         const char *service, 
1129         const char *realm, 
1130         const char **attrs, 
1131         LAK_RESULT **ret)
1132 {
1133         int rc = 0, i;
1134         char *filter = NULL;
1135         char *search_base = NULL;
1136         LDAPMessage *res = NULL;
1137         LDAPMessage *entry = NULL;
1138         BerElement *ber = NULL;
1139         char *attr = NULL, **vals = NULL, *dn = NULL;
1140         LAK_USER *lu = NULL;
1141     
1142         *ret = NULL;
1143
1144         if (lak == NULL) {
1145                 syslog(LOG_ERR|LOG_AUTH, "lak_init did not run.");
1146                 return LAK_FAIL;
1147         }
1148
1149         if (EMPTY(user))
1150                 return LAK_FAIL;
1151
1152         if (EMPTY(realm))
1153                 realm = lak->conf->default_realm;
1154
1155         rc = lak_user(  
1156                 lak->conf->bind_dn,
1157                 lak->conf->id,
1158                 lak->conf->authz_id,
1159                 lak->conf->mech,
1160                 lak->conf->realm,
1161                 lak->conf->password,
1162                 &lu);
1163         if (rc != LAK_OK)
1164                 return rc;
1165
1166         rc = lak_bind(lak, lu);
1167         if (rc != LAK_OK)
1168                 goto done;
1169
1170         rc = lak_expand_tokens(lak->conf->filter, user, service, realm, NULL, &filter);
1171         if (rc != LAK_OK)
1172         goto done;
1173
1174         rc = lak_expand_tokens(lak->conf->search_base, user, service, realm, NULL, &search_base);
1175         if (rc != LAK_OK)
1176         goto done;
1177
1178         rc = ldap_search_st(lak->ld, search_base, lak->conf->scope, filter, (char **) attrs, 0, &(lak->conf->timeout), &res);
1179         switch (rc) {
1180                 case LDAP_SUCCESS:
1181                 case LDAP_NO_SUCH_OBJECT:
1182                         break;
1183                 case LDAP_TIMELIMIT_EXCEEDED:
1184                 case LDAP_BUSY:
1185                 case LDAP_UNAVAILABLE:
1186                 case LDAP_INSUFFICIENT_ACCESS:
1187                         /*  We do not need to re-connect to the LDAP server 
1188                             under these conditions */
1189                         syslog(LOG_ERR|LOG_AUTH, "user ldap_search_st() failed: %s", ldap_err2string(rc));
1190             rc = LAK_USER_NOT_FOUND;
1191                         goto done;
1192                 case LDAP_TIMEOUT:
1193                 case LDAP_SERVER_DOWN:
1194                 default:
1195                         syslog(LOG_ERR|LOG_AUTH, "user ldap_search_st() failed: %s", ldap_err2string(rc));
1196             rc = LAK_RETRY;
1197                         lak->status = LAK_NOT_BOUND;
1198                         goto done;
1199         }
1200
1201     i = ldap_count_entries(lak->ld, res);
1202     if (i != 1) {
1203         if (i == 0)
1204                         syslog(LOG_DEBUG|LOG_AUTH, "Entry not found (%s).", filter);
1205         else
1206             syslog(LOG_DEBUG|LOG_AUTH, "Duplicate entries found (%s).", filter);
1207         rc = LAK_USER_NOT_FOUND;
1208         goto done;
1209     }
1210         
1211     rc = LAK_FAIL;
1212
1213         if ((entry = ldap_first_entry(lak->ld, res)) != NULL)  {
1214         for (i=0; attrs[i] != NULL; i++) {
1215             
1216             if (!strcmp(attrs[i], dn_attr)) {
1217                 dn = ldap_get_dn(lak->ld, entry);
1218                 if (dn == NULL)
1219                     goto done;
1220
1221                 rc = lak_result_add(dn_attr, dn, ret);
1222                 if (rc != LAK_OK) {
1223                     lak_result_free(*ret);
1224                     *ret = NULL;
1225                     goto done;
1226                 }
1227             }
1228         }
1229
1230         for (attr = ldap_first_attribute(lak->ld, entry, &ber); attr != NULL; 
1231             attr = ldap_next_attribute(lak->ld, entry, ber)) {
1232
1233             vals = ldap_get_values(lak->ld, entry, attr);
1234             if (vals == NULL)
1235                 continue;
1236
1237             for (i = 0; vals[i] != NULL; i++) {
1238                 rc = lak_result_add(attr, vals[i], ret);
1239                 if (rc != LAK_OK) {
1240                     lak_result_free(*ret);
1241                     *ret = NULL;
1242                     goto done;
1243                 }
1244             }
1245
1246             ldap_value_free(vals);
1247             vals = NULL;
1248             ldap_memfree(attr);
1249             attr = NULL;
1250         }
1251     }
1252
1253 done:;
1254         if (res)
1255                 ldap_msgfree(res);
1256         if (dn)
1257                 ldap_memfree(dn);
1258         if (vals)
1259                 ldap_value_free(vals);
1260         if (attr)
1261                 ldap_memfree(attr);
1262         if (ber != NULL)
1263                 ber_free(ber, 0);
1264         if (filter)
1265                 free(filter);
1266         if (search_base)
1267                 free(search_base);
1268         if (lu)
1269                 lak_user_free(lu);
1270
1271         return rc;
1272 }
1273
1274 static int lak_group_member(
1275         LAK *lak, 
1276         const char *user, 
1277         const char *service, 
1278         const char *realm, 
1279         const char *dn)
1280 {
1281         char *group_dn = NULL, *user_dn = NULL;
1282     char *group_filter = NULL;
1283     char *group_search_base = NULL;
1284         struct berval *dn_bv = NULL;
1285         int rc;
1286     LAK_RESULT *lres = NULL;
1287     const char *attrs[] = { dn_attr, NULL };
1288     const char *group_attrs[] = {"1.1", NULL};
1289
1290         LDAPMessage *res = NULL;
1291
1292     user_dn = (char *)dn;
1293
1294     if (EMPTY(user_dn)) {
1295         if (lak->conf->use_sasl) {
1296
1297 #if LDAP_VENDOR_VERSION >= 20122
1298             if (ldap_whoami_s(lak->ld, &dn_bv, NULL, NULL) != LDAP_SUCCESS || !dn_bv) {
1299                 syslog(LOG_ERR|LOG_AUTH, "ldap_whoami_s() failed.");
1300                 rc =  LAK_NOT_GROUP_MEMBER;
1301                 goto done;
1302             }
1303
1304             user_dn = dn_bv->bv_val;
1305 #else
1306             syslog(LOG_ERR|LOG_AUTH, "Your OpenLDAP API does not supported ldap_whoami().");
1307             rc =  LAK_NOT_GROUP_MEMBER;
1308             goto done;
1309 #endif
1310
1311         } else {
1312             
1313             rc = lak_retrieve(lak, user, service, realm, attrs, &lres);
1314             if (rc != LAK_OK)
1315                 goto done;
1316
1317             user_dn = lres->value;
1318         }
1319     }
1320
1321     if (lak->conf->group_match_method == LAK_GROUP_MATCH_METHOD_ATTR) {
1322
1323             rc = lak_expand_tokens(lak->conf->group_dn, user, service, realm, NULL, &group_dn);
1324             if (rc != LAK_OK)
1325                 goto done;
1326
1327             rc = ((ldap_compare_s(lak->ld, group_dn, lak->conf->group_attr, user_dn)) == LDAP_COMPARE_TRUE ? 
1328                      LAK_OK : LAK_NOT_GROUP_MEMBER);
1329
1330     } else if (lak->conf->group_match_method == LAK_GROUP_MATCH_METHOD_FILTER) {
1331
1332         rc = lak_expand_tokens(lak->conf->group_filter, user, service, realm, user_dn, &group_filter);
1333         if (rc != LAK_OK)
1334             goto done;
1335
1336         rc = lak_expand_tokens(lak->conf->group_search_base, user, service, realm, user_dn, &group_search_base);
1337         if (rc != LAK_OK)
1338             goto done;
1339
1340         rc = ldap_search_st(lak->ld, group_search_base, lak->conf->group_scope, group_filter, (char **) group_attrs, 0, &(lak->conf->timeout), &res);
1341         switch (rc) {
1342             case LDAP_SUCCESS:
1343             case LDAP_NO_SUCH_OBJECT:
1344                 break;
1345             case LDAP_TIMELIMIT_EXCEEDED:
1346             case LDAP_BUSY:
1347             case LDAP_UNAVAILABLE:
1348             case LDAP_INSUFFICIENT_ACCESS:
1349                 syslog(LOG_ERR|LOG_AUTH, "group ldap_search_st() failed: %s", ldap_err2string(rc));
1350                 rc = LAK_NOT_GROUP_MEMBER;
1351                 goto done;
1352             case LDAP_TIMEOUT:
1353             case LDAP_SERVER_DOWN:
1354             default:
1355                 syslog(LOG_ERR|LOG_AUTH, "group ldap_search_st() failed: %s", ldap_err2string(rc));
1356                 rc = LAK_RETRY;
1357                 lak->status = LAK_NOT_BOUND;
1358                 goto done;
1359         }
1360
1361         rc = ( (ldap_count_entries(lak->ld, res) >= 1) ? LAK_OK : LAK_NOT_GROUP_MEMBER );
1362
1363     } else {
1364
1365             syslog(LOG_WARNING|LOG_AUTH, "Unknown ldap_group_match_method value.");
1366             rc = LAK_FAIL;
1367
1368     }
1369
1370 done:;
1371         if (res)
1372                 ldap_msgfree(res);
1373     if (group_dn)
1374         free(group_dn);
1375     if (group_filter)
1376         free(group_filter);
1377     if (group_search_base)
1378         free(group_search_base);
1379     if (lres)
1380         lak_result_free(lres);
1381     if (dn_bv)
1382         ber_bvfree(dn_bv);
1383
1384         return rc;
1385 }
1386
1387 static int lak_auth_custom(
1388         LAK *lak,
1389         const char *user,
1390         const char *service,
1391         const char *realm,
1392         const char *password) 
1393 {
1394         LAK_RESULT *lres;
1395         int rc;
1396         const char *attrs[] = { lak->conf->password_attr, NULL};
1397
1398         rc = lak_retrieve(lak, user, service, realm, attrs, &lres);
1399         if (rc != LAK_OK)
1400                 return rc;
1401
1402     rc = lak_check_password(lres->value, password, NULL);
1403
1404         if ( rc == LAK_OK &&
1405             (ISSET(lak->conf->group_dn) ||
1406          ISSET(lak->conf->group_filter)) )
1407         rc = lak_group_member(lak, user, service, realm, NULL);
1408         
1409         lak_result_free(lres);
1410
1411         return(rc);
1412 }
1413
1414 static int lak_auth_bind(
1415         LAK *lak,
1416         const char *user,
1417         const char *service,
1418         const char *realm,
1419         const char *password) 
1420 {
1421     LAK_USER *lu = NULL;
1422         LAK_RESULT *dn = NULL;
1423         int rc;
1424         const char *attrs[] = {dn_attr, NULL};
1425
1426         rc = lak_retrieve(lak, user, service, realm, attrs, &dn);
1427         if (rc != LAK_OK)
1428                 goto done;
1429
1430         rc = lak_user(  
1431                 dn->value,
1432                 NULL,
1433                 NULL,
1434                 NULL,
1435                 NULL,
1436                 password,
1437                 &lu);
1438         if (rc != LAK_OK)
1439                 goto done;
1440
1441         rc = lak_bind(lak, lu);
1442
1443         if ( rc == LAK_OK &&
1444             (ISSET(lak->conf->group_dn) ||
1445          ISSET(lak->conf->group_filter)) )
1446                 rc = lak_group_member(lak, user, service, realm, dn->value);
1447
1448 done:;
1449         if (lu)
1450                 lak_user_free(lu);
1451         if (dn)
1452                 lak_result_free(dn);
1453
1454         return rc;
1455 }
1456
1457 static int lak_auth_fastbind(
1458         LAK *lak,
1459         const char *user,
1460         const char *service,
1461         const char *realm,
1462         const char *password) 
1463 {
1464         int rc;
1465         LAK_USER *lu = NULL;
1466         char *dn = NULL;
1467         char id[LAK_BUF_LEN];
1468
1469         *id = '\0';
1470
1471         if (lak->conf->use_sasl) {
1472                 strlcpy(id, user, LAK_BUF_LEN);
1473                 if (!strchr(id, '@') &&
1474                     (ISSET(realm))) {
1475                         strlcat(id, "@", LAK_BUF_LEN);
1476                         strlcat(id, realm, LAK_BUF_LEN);
1477                 }
1478         } else {
1479                 rc = lak_expand_tokens(lak->conf->filter, user, service, realm, NULL, &dn);
1480                 if (rc != LAK_OK || 
1481             EMPTY(dn))
1482                         goto done;
1483         }
1484                         
1485         rc = lak_user(  
1486                 dn,
1487                 id,
1488                 NULL,
1489                 lak->conf->mech,
1490                 lak->conf->realm,
1491                 password,
1492                 &lu);
1493         if (rc != LAK_OK)
1494                 goto done;
1495
1496         rc = lak_bind(lak, lu);
1497
1498         if ( rc == LAK_OK &&
1499             (ISSET(lak->conf->group_dn) ||
1500          ISSET(lak->conf->group_filter)) )
1501             rc = lak_group_member(lak, user, service, realm, dn);
1502
1503 done:;
1504         if (lu)
1505                 lak_user_free(lu);
1506         if (dn != NULL)
1507                 free(dn);
1508
1509         return rc;
1510 }
1511
1512 int lak_authenticate(
1513         LAK *lak,
1514         const char *user,
1515         const char *service,
1516         const char *realm,
1517         const char *password) 
1518 {
1519         int i;
1520         int rc;
1521     int retry = 2;
1522
1523         if (lak == NULL) {
1524                 syslog(LOG_ERR|LOG_AUTH, "lak_init did not run.");
1525                 return LAK_FAIL;
1526         }
1527
1528         if (EMPTY(user))
1529                 return LAK_FAIL;
1530
1531         if (EMPTY(realm))
1532                 realm = lak->conf->default_realm;
1533
1534         for (i = 0; authenticator[i].method != -1; i++) {
1535                 if (authenticator[i].method == lak->conf->auth_method) {
1536                         if (authenticator[i].check) {
1537                 for (;retry > 0; retry--) {
1538                     rc = (authenticator[i].check)(lak, user, service, realm, password);
1539                     switch(rc) {
1540                         case LAK_OK:
1541                             return LAK_OK;
1542                         case LAK_RETRY:
1543                             if (retry > 1) {
1544                                 syslog(LOG_INFO|LOG_AUTH, "Retrying authentication");
1545                                 break;
1546                             }
1547                         default:
1548                             syslog(
1549                                 LOG_DEBUG|LOG_AUTH, 
1550                                 "Authentication failed for %s%s%s: %s (%d)", 
1551                                 user, 
1552                                 (ISSET(realm) ? "/" : ""), 
1553                                 (ISSET(realm) ? realm : ""), 
1554                                 lak_error(rc), 
1555                                 rc);
1556                             return LAK_FAIL;
1557                     }
1558                 }
1559             }
1560                         break;
1561                 }
1562         }
1563
1564     /* Should not get here */
1565     syslog(LOG_DEBUG|LOG_AUTH, "Authentication method not setup properly (%d)", lak->conf->auth_method);
1566
1567         return LAK_FAIL;
1568 }
1569
1570 char *lak_error(
1571     const int errno)
1572 {
1573
1574     switch (errno) {
1575         case LAK_OK:
1576             return "Success";
1577         case LAK_FAIL:
1578             return "Generic error";
1579         case LAK_NOMEM:
1580             return "Out of memory";
1581         case LAK_RETRY:
1582             return "Retry condition (ldap server connection reset or broken)";
1583         case LAK_NOT_GROUP_MEMBER:
1584             return "Group member check failed";
1585         case LAK_INVALID_PASSWORD:
1586             return "Invalid password";
1587         case LAK_USER_NOT_FOUND:
1588             return "User not found";
1589         case LAK_BIND_FAIL:
1590             return "Bind to ldap server failed (invalid user/password or insufficient access)";
1591         case LAK_CONNECT_FAIL:
1592             return "Cannot connect to ldap server (configuration error)";
1593         default:
1594             return "Unknow error";
1595     }
1596 }
1597
1598 static char *lak_result_get(
1599     const LAK_RESULT *lres, 
1600     const char *attr) 
1601 {
1602     LAK_RESULT *ptr;
1603
1604
1605     for (ptr = (LAK_RESULT *)lres; ptr != NULL; ptr = ptr->next)
1606         if (!strcasecmp(ptr->attribute, attr))
1607             return ptr->value;
1608
1609     return NULL;
1610 }
1611
1612 static int lak_result_add(
1613         const char *attr,
1614         const char *val,
1615         LAK_RESULT **ret)  
1616 {
1617         LAK_RESULT *lres;
1618         
1619         lres = (LAK_RESULT *) malloc(sizeof(LAK_RESULT));
1620         if (lres == NULL) {
1621                 return LAK_NOMEM;
1622         }
1623
1624         lres->next = NULL;
1625
1626         lres->attribute = strdup(attr);
1627         if (lres->attribute == NULL) {
1628                 lak_result_free(lres);
1629                 return LAK_NOMEM;
1630         }
1631
1632         lres->value = strdup(val);
1633         if (lres->value == NULL) {
1634                 lak_result_free(lres);
1635                 return LAK_NOMEM;
1636         }
1637         lres->len = strlen(lres->value);
1638
1639         lres->next = *ret;
1640
1641         *ret = lres;
1642         return LAK_OK;
1643 }
1644
1645 void lak_result_free(
1646         LAK_RESULT *res) 
1647 {
1648         LAK_RESULT *lres, *ptr = res;
1649
1650         if (ptr == NULL)
1651                 return;
1652
1653         for (lres = ptr; lres != NULL; lres = ptr) {
1654
1655                 ptr = lres->next;
1656
1657                 if (lres->attribute != NULL) {
1658                         memset(lres->attribute, 0, strlen(lres->attribute));
1659                         free(lres->attribute);  
1660                 }
1661
1662                 if (lres->value != NULL) {
1663                         memset(lres->value, 0, strlen(lres->value));
1664                         free(lres->value);      
1665                 }
1666
1667                 lres->next = NULL;
1668
1669                 free(lres);
1670         }
1671
1672         return;
1673 }
1674
1675 static int lak_check_password(
1676         const char *hash, 
1677         const char *passwd,
1678         void *rock __attribute__((unused))) 
1679 {
1680         int i, hlen;
1681
1682         if (EMPTY(hash))
1683                 return LAK_INVALID_PASSWORD;
1684
1685         if (EMPTY(passwd))
1686                 return LAK_INVALID_PASSWORD;
1687
1688         for (i = 0; password_scheme[i].hash != NULL; i++) {
1689
1690                 hlen = strlen(password_scheme[i].hash);
1691                 if (!strncasecmp(password_scheme[i].hash, hash, hlen)) {
1692                         if (password_scheme[i].check) {
1693                                 return (password_scheme[i].check)(hash+hlen, passwd,
1694                                                                 password_scheme[i].rock);
1695                         }
1696                         return LAK_FAIL;
1697                 }
1698         }
1699
1700         return strcmp(hash, passwd) ? LAK_INVALID_PASSWORD : LAK_OK;
1701 }
1702
1703 #ifdef HAVE_OPENSSL
1704
1705 static int lak_base64_decode(
1706         const char *src,
1707         char **ret,
1708         int *rlen) 
1709 {
1710
1711         int rc, i, tlen = 0;
1712         char *text;
1713         EVP_ENCODE_CTX EVP_ctx;
1714
1715         text = (char *)malloc(((strlen(src)+3)/4 * 3) + 1);
1716         if (text == NULL)
1717                 return LAK_NOMEM;
1718
1719         EVP_DecodeInit(&EVP_ctx);
1720         rc = EVP_DecodeUpdate(&EVP_ctx, text, &i, (char *)src, strlen(src));
1721         if (rc < 0) {
1722                 free(text);
1723                 return LAK_FAIL;
1724         }
1725         tlen += i;
1726         EVP_DecodeFinal(&EVP_ctx, text, &i); 
1727
1728         *ret = text;
1729         if (rlen != NULL)
1730                 *rlen = tlen;
1731
1732         return LAK_OK;
1733 }
1734
1735 static int lak_check_hashed(
1736         const char *hash,
1737         const char *passwd,
1738         void *rock)
1739 {
1740         int rc, clen;
1741         LAK_HASH_ROCK *hrock = (LAK_HASH_ROCK *) rock;
1742         EVP_MD_CTX mdctx;
1743         const EVP_MD *md;
1744         unsigned char digest[EVP_MAX_MD_SIZE];
1745         char *cred;
1746
1747         md = EVP_get_digestbyname(hrock->mda);
1748         if (!md)
1749                 return LAK_FAIL;
1750
1751         rc = lak_base64_decode(hash, &cred, &clen);
1752         if (rc != LAK_OK)
1753                 return rc;
1754
1755         EVP_DigestInit(&mdctx, md);
1756         EVP_DigestUpdate(&mdctx, passwd, strlen(passwd));
1757         if (hrock->salted) {
1758                 EVP_DigestUpdate(&mdctx, &cred[EVP_MD_size(md)],
1759                                  clen - EVP_MD_size(md));
1760         }
1761         EVP_DigestFinal(&mdctx, digest, NULL);
1762
1763         rc = memcmp((char *)cred, (char *)digest, EVP_MD_size(md));
1764         free(cred);
1765         return rc ? LAK_INVALID_PASSWORD : LAK_OK;
1766 }
1767
1768 #endif /* HAVE_OPENSSL */
1769
1770 static int lak_check_crypt(
1771         const char *hash,
1772         const char *passwd,
1773         void *rock __attribute__((unused))) 
1774 {
1775         char *cred;
1776
1777         if (strlen(hash) < 2 )
1778                 return LAK_INVALID_PASSWORD;
1779
1780         cred = crypt(passwd, hash);
1781         if (EMPTY(cred))
1782                 return LAK_INVALID_PASSWORD;
1783
1784         return strcmp(hash, cred) ? LAK_INVALID_PASSWORD : LAK_OK;
1785 }
1786
1787 #endif /* AUTH_LDAP */