Import Debian changes 0.66.4-9
[hcoop/debian/courier-authlib.git] / authldaplib.c
CommitLineData
d9898ee8 1/*
2 * authldap.c -
3 *
4 * courier-imap -
5 *
6 * Copyright 1999 Luc Saillard <luc.saillard@alcove.fr>.
7 *
8 * This module use a server LDAP to authenticate user.
9 * See the README.ldap
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; see the file COPYING. If not, write to
b0322a85
CE
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
25 * Boston, MA 02110-1301, USA.
d9898ee8 26 */
27
28/*
29 * Modified 28/11/2001 Iustin Pop <iusty@intensit.de>
30 * There was a bug regarding the LDAP_TLS option: if both LDAP_TLS
31 * and was LDAP_AUTHBIND were enabled, the ldap_start_tls function
32 * was called only for the first connection, resulting in the fact
33 * that the bind for checking the password was done without TLS,
34 * sending the password in clear text over the network. Detected
35 * when using OpenLDAP with "security ssf=128" (which disalows any
36 * clear-text communication).
37*/
38
39/*
40 Modified 01/21/2000 James Golovich <james@wwnet.net>
41
421. If LDAP_AUTHBIND is set in the config file, then the ldap server will
43handle passwords via authenticated binds, instead of checking these
44internally.
452. Changed paramaters for authldap_get to include pass.
46
47*/
48
49/*
50 Modified 12/31/99 Sam Varshavchik:
51
521. read_env reads from a configuration file, instead of the environment
532. read_config appropriately modified.
543. If 'user' contains the @ character, domain from config is NOT appended.
554. added 'homeDir' attribute. Use 'homeDir' instead of mailDir, and put
56 mailDir into MAILDIR=
575. read_config renamed to authldap_read_config
586. get_user_info renamed to authldap_get
597. Added authldap_free_config, to clean up all the allocated memory
60 (required for preauthldap).
618. Output LDAP attributes are defined in the configuration file as well.
629. Allow both plaintext and crypted passwords to be read from LDAP.
6310. Added GLOB_UID GLOB_GID, as well as UID and GID params.
64
652/19/2000 Sam.
66
67Rewrite to allow this code to be used in a long-running authentication daemon
68(for Courier). authldap_get renamed to authldapcommon, will initialize and
69maintain a persistent connection. Password checking moved entirely to
70authldap.c. authldapclose() will unbind and close the connection.
71
72connection gets closed and reopened automatically after a protocol error.
73
74error return from authldapcommon will indicate whether this is a transient,
75or a permanent failure.
76
77authldap_free_config removed - no longer required.
78
79*/
80
81#if HAVE_CONFIG_H
82#include "courier_auth_config.h"
83#endif
84#include <stdio.h>
85#include <stdlib.h>
86#include <ctype.h>
87#include <string.h>
88#include <errno.h>
89#include <pwd.h>
90#include <grp.h>
91#include <time.h>
92#if HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95#if HAVE_LBER_H
96#include <lber.h>
97#endif
98#if HAVE_LDAP_H
99#include <ldap.h>
100#if LDAP_VENDOR_VERSION > 20000
101#define OPENLDAPV2
102#endif
103#endif
104#if HAVE_SYS_TIME_H
105#include <sys/time.h>
106#endif
107#if HAVE_SYS_STAT_H
108#include <sys/stat.h>
109#endif
110
111#include "authldap.h"
112#include "auth.h"
113#include "authldaprc.h"
114#include "courierauthdebug.h"
115
116#define err courier_auth_err
117
118#ifndef DEBUG_LDAP
119#define DEBUG_LDAP 0
120#endif
121
122#ifndef LDAP_OPT_SUCCESS
123#define LDAP_OPT_SUCCESS LDAP_SUCCESS
124#endif
125
126static char **l_get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
127{
128 struct berval **p=ldap_get_values_len(ld, entry, attribut);
ac40fd9e 129 int i, n;
d9898ee8 130 char **a;
131
132 if (!p)
133 return NULL;
134
135 n=ldap_count_values_len(p);
136
137
138 a=malloc((n + 1) * sizeof(char *));
139
140 if (!a)
141 {
142 DPRINTF("malloc failed");
143 ldap_value_free_len(p);
144 return NULL;
145 }
146
d9898ee8 147 for (i=0; i<n; i++)
148 {
149 if ((a[i]=malloc(p[i]->bv_len+1)) == NULL)
150 {
151 DPRINTF("malloc failed");
152 while (i--)
153 {
154 free(a[i]);
155 }
156 free(a);
157 ldap_value_free_len(p);
158 return NULL;
159 }
160
161 memcpy(a[i], p[i]->bv_val, p[i]->bv_len);
162 a[i][p[i]->bv_len]=0;
163 }
164
165 ldap_value_free_len(p);
166 a[i]=NULL;
167 return a;
168}
169
170static void l_value_free(char **p)
171{
172 int i;
173
174 for (i=0; p[i]; ++i)
175 free(p[i]);
176 free(p);
177}
178
179static int l_count_values(char **p)
180{
181 int i;
182
183 for (i=0; p[i]; ++i)
184 ;
185 return i;
186}
187
188static int l_unbind(LDAP *ld)
189{
190 return ldap_unbind_ext(ld, NULL, NULL);
191}
192
193static int l_simple_bind_s(LDAP *ld,
194 const char *who,
195 const char *passwd)
196{
197 struct berval cred;
198
199 cred.bv_len=passwd ? strlen(passwd):0;
200 cred.bv_val=(char *)passwd;
201
202 return ldap_sasl_bind_s(ld, who, NULL, &cred, NULL, NULL, NULL);
203}
204
205static int l_search_st(LDAP *ld,
206 const char *base,
207 int scope,
208 const char *filter,
209 char **attrs,
210 int attrsonly,
211 struct timeval *timeout,
212 LDAPMessage **res)
213{
214 return ldap_search_ext_s(ld, base, scope, filter, attrs,
215 attrsonly,
216 NULL, NULL,
217 timeout,
218 100,
219 res);
220}
221
222static int l_modify_s(LDAP *ld,
223 const char *dn,
224 LDAPMod **mods)
225{
226 return ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
227}
228
229static int l_search(LDAP *ld,
230 const char *base,
231 int scope,
232 const char *filter,
233 char **attrs,
234 int attrsonly)
235{
236 struct timeval tv;
237 int msgid;
238
239 tv.tv_sec=60*60;
240 tv.tv_usec=0;
241
242 if (ldap_search_ext(ld, base, scope, filter, attrs, attrsonly,
243 NULL, NULL, &tv, 1000000, &msgid) !=
244 LDAP_SUCCESS)
245 return -1;
246
247 return msgid;
248}
249
250struct ldap_info
251{
252 const char *uri;
253 const char *binddn;
254 const char *bindpw;
255 const char *basedn;
256 const char *mail;
257 const char *filter;
258 const char *enumerate_filter;
259 const char *domain;
260
261 uid_t uid;
262 gid_t gid;
263 int timeout;
264 int authbind;
b0322a85 265 int initbind;
d9898ee8 266 int deref;
267 int protocol_version;
268 int tls;
269
270 const char *mailroot;
271
272 char **auxoptions;
273 char **auxnames;
274 const char **attrlist;
275
276 /* Optional emailmap to handle */
277
278 const char *emailmap;
279 const char *emailmap_basedn;
280 const char *emailmap_handle;
281 const char *emailmap_handle_lookup;
282};
283
284/*
285** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
286** too. See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
287** information. To work around the bug, the first time a connection fails
288** we stop trying for 60 seconds. After 60 seconds we kill the process,
289** and let the parent process restart it.
290**
291** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
292** off this behavior (whenever OpenLDAP gets fixed).
293*/
294
295static time_t ldapfailflag=0;
296
297static void ldapconnfailure()
298{
299 const char *p=getenv("LDAP_MEMORY_LEAK");
300
301 if (!p)
302 {
303#ifdef LDAP_VENDOR_NAME
304#ifdef LDAP_VENDOR_VERSION
305#define DO_OPENLDAP_CHECK
306#endif
307#endif
308
309#ifdef DO_OPENLDAP_CHECK
310
311 /* It's supposed to be fixed in 20019 */
312
313 if (strcmp(LDAP_VENDOR_NAME, "OpenLDAP") == 0 &&
314 LDAP_VENDOR_VERSION < 20019)
315 p="1";
316 else
317 p="0";
318#else
319 p="0";
320#endif
321 }
322
323 if (atoi(p) && !ldapfailflag)
324 {
325 time(&ldapfailflag);
326 ldapfailflag += 60;
327 }
328}
329
330static int ldapconncheck()
331{
332 time_t t;
333
334 if (!ldapfailflag)
335 return (0);
336
337 time(&t);
338
339 if (t >= ldapfailflag)
340 exit(0);
341 return (1);
342}
343
344static int read_env(const char *env, const char **copy,
345 const char *errstr, int needit, const char *value_default);
346static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
347 char **copy, const char *username);
348
349/*
350 * Function: read_env
351 * Copy the environnement $env and copy to $copy if not null
352 * if needit is false, and env doesn't exist, copy $value_default to $copy
353 * INPUT:
354 * $env: pointer to the environnement name
355 * $copy: where the value go
356 * $err: print a nice message when $env not_found and $needit is true
357 * $needit: if $needit is true and $value not found, return a error
358 * $value_default: the default value when $needit is false and $env doesn't exists
359 * OUTPUT:
360 * boolean
361 */
362static int read_env(const char *env, const char **copy,
363 const char *errstr, int needit, const char *value_default)
364{
365static char *ldapauth=0;
366static size_t ldapauth_size=0;
367size_t i;
368char *p=0;
369int l=strlen(env);
370
371 if (!ldapauth)
372 {
373 FILE *f=fopen(AUTHLDAPRC, "r");
374 struct stat buf;
375
376 if (!f) return (0);
377 if (fstat(fileno(f), &buf) ||
378 (ldapauth=malloc(buf.st_size+2)) == 0)
379 {
380 fclose(f);
381 return (0);
382 }
383 if (fread(ldapauth, buf.st_size, 1, f) != 1)
384 {
385 free(ldapauth);
386 ldapauth=0;
387 fclose(f);
388 return (0);
389 }
390 ldapauth[ldapauth_size=buf.st_size]=0;
391
392 for (i=0; i<ldapauth_size; i++)
393 if (ldapauth[i] == '\n')
394 ldapauth[i]=0;
8d138742 395 fclose(f);
d9898ee8 396 }
397
398 for (i=0; i<ldapauth_size; )
399 {
400 p=ldapauth+i;
401 if (memcmp(p, env, l) == 0 &&
402 isspace((int)(unsigned char)p[l]))
403 {
404 p += l;
405 while (*p && *p != '\n' &&
406 isspace((int)(unsigned char)*p))
407 ++p;
408 break;
409 }
410
411 while (i < ldapauth_size)
412 if (ldapauth[i++] == 0) break;
413 }
414
415 if (i < ldapauth_size)
416 {
417 *copy= p;
418 return (1);
419 }
420
421 if (needit)
422 {
423 err("%s", errstr);
424 return 0;
425 }
426
427 *copy=0;
428 if (value_default)
429 *copy=value_default;
430
431 return 1;
432}
433
434/*
435 * Function: authldap_read_config
436 * Read Configuration from the environnement table
437 * INPUT:
438 * $ldap: a structure where we place information
439 * OUTPUT:
440 * boolean
441 */
442static int authldap_read_config(struct ldap_info *ldap)
443{
444 struct passwd *pwent;
445 struct group *grent;
446 const char *p;
447 size_t i, pass;
448
449 for (i=0; ldap->auxoptions && ldap->auxoptions[i]; i++)
450 free(ldap->auxoptions[i]);
451 for (i=0; ldap->auxnames && ldap->auxnames[i]; i++)
452 free(ldap->auxnames[i]);
453
454 if (ldap->attrlist)
455 free(ldap->attrlist);
456 if (ldap->auxnames)
457 free(ldap->auxnames);
458 if (ldap->auxoptions)
459 free(ldap->auxoptions);
460
461 memset(ldap,0,sizeof(struct ldap_info));
462
463 if (!read_env("LDAP_URI",&ldap->uri,
464 "You need to specify LDAP_URI in config file",1,NULL))
465 return 0;
466
467 if (!read_env("LDAP_AUTHBIND", &p, "", 0, ""))
468 return (0);
469
470 if (p)
471 sscanf(p,"%d",&ldap->authbind);
472
b0322a85
CE
473 if (!read_env("LDAP_INITBIND", &p, "", 0, "1"))
474 return (0);
475
476 if (p)
477 sscanf(p,"%d",&ldap->initbind);
478
d9898ee8 479 if (!read_env("LDAP_BASEDN",&ldap->basedn,
480 "You need to specify a basedn in config file",1,NULL))
481 return 0;
482 if (!read_env("LDAP_BINDDN",&ldap->binddn,
483 "You need to specify a BINDDN in config file",0,NULL))
484 return 0;
485 if (!read_env("LDAP_BINDPW",&ldap->bindpw,
486 "You need to specify a password for the BINDDN in config file",0,NULL))
487 return 0;
488 if (!read_env("LDAP_MAIL",&ldap->mail,
489 "You need to specify a attribute for mail in config file",0,"mail"))
490 return 0;
491 if (!read_env("LDAP_DOMAIN",&ldap->domain,
492 "You need to specify a domain for mail in config file",0,""))
493 return 0;
494
495 p=0;
496 ldap->uid=0;
497 if (!read_env("LDAP_GLOB_UID", &p, "", 0, ""))
498 return (0);
499
500 if (p && *p)
501 {
502 unsigned long n;
503
504 if (sscanf(p, "%lu", &n) == 1)
505 ldap->uid=(uid_t)n;
506 else
507 {
508 pwent=getpwnam(p);
509 if (!pwent)
510 {
511 err("authldap: INVALID LDAP_GLOB_UID");
512 return (0);
513 }
514 ldap->uid=pwent->pw_uid;
515 }
516 }
517
518 ldap->gid=0;
519 p=0;
520 if (!read_env("LDAP_GLOB_GID", &p, "", 0, ""))
521 return (0);
522
523 if (p && *p)
524 {
525 unsigned long n;
526
527 if (sscanf(p, "%lu", &n) == 1)
528 ldap->gid=(gid_t)n;
529 else
530 {
531 grent=getgrnam(p);
532 if (!grent)
533 {
534 err("authldap: INVALID LDAP_GLOB_GID");
535 return (0);
536 }
537 ldap->gid=grent->gr_gid;
538 }
539 }
540
541 ldap->timeout=5;
542 p=0;
543 if (read_env("LDAP_TIMEOUT", &p, "", 0, "") && p)
544 {
545 sscanf(p,"%d",&ldap->timeout);
546 }
547
548 ldap->tls=0;
549 p=0;
550 if (read_env("LDAP_TLS", &p, "", 0, "") && p)
551 {
552 ldap->tls=atoi(p);
553 }
554
555 ldap->filter=0;
556 p=0;
557 if (read_env("LDAP_FILTER", &p, "", 0, "") && p && strlen (p))
558 {
559 ldap->filter=p;
560 }
561
562 ldap->enumerate_filter=0;
563 p=0;
564 if (read_env("LDAP_ENUMERATE_FILTER", &p, "", 0, "") && p && strlen (p))
565 {
566 ldap->enumerate_filter=p;
567 }
568 else if (ldap->filter)
569 {
570 ldap->enumerate_filter=ldap->filter;
571 }
572 else
573 {
574 ldap->enumerate_filter = malloc(strlen(ldap->mail)+3);
575 if (!ldap->enumerate_filter)
576 {
577 perror("CRIT: authldap: malloc failed");
578 return 0;
579 }
580 sprintf((char *)ldap->enumerate_filter, "%s=*", ldap->mail);
581 }
582
583 ldap->deref = LDAP_DEREF_NEVER;
584 ldap->protocol_version = 0; /* use API default */
585 p=0;
586 if (!read_env("LDAP_DEREF", &p, "", 0, ""))
587 return (0);
588 if (p)
589 {
590#ifndef LDAP_OPT_DEREF
591 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
592#endif
593 if (!strcasecmp (p, "never"))
594 ldap->deref = LDAP_DEREF_NEVER;
595 else if (!strcasecmp (p, "searching"))
596 ldap->deref = LDAP_DEREF_SEARCHING;
597 else if (!strcasecmp (p, "finding"))
598 ldap->deref = LDAP_DEREF_FINDING;
599 else if (!strcasecmp (p, "always"))
600 ldap->deref = LDAP_DEREF_ALWAYS;
601 }
602
603 if (!read_env("LDAP_PROTOCOL_VERSION", &p, 0, 0, 0))
604 return (0);
605 if (p)
606 {
607 int lpv = atoi(p);
608#ifndef LDAP_OPT_PROTOCOL_VERSION
609 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
610#endif
611 if (lpv == 0
612#ifdef LDAP_VERSION_MIN
613 || lpv < LDAP_VERSION_MIN
614#endif
615#ifdef LDAP_VERSION_MAX
616 || lpv > LDAP_VERSION_MAX
617#endif
618 )
619 err("authldaplib: illegal protocol version ignored");
620 else
621 ldap->protocol_version = lpv;
622 }
623
624 if (!read_env("LDAP_MAILROOT",&ldap->mailroot,"",0,NULL)
625 || ldap->mailroot == NULL || ldap->mailroot[0] == 0)
626 ldap->mailroot=NULL;
627
628 if (!read_env("LDAP_EMAILMAP", &ldap->emailmap, "", 0, "") ||
629 !read_env("LDAP_EMAILMAP_BASEDN", &ldap->emailmap_basedn, "", 0, "") ||
630 !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap->emailmap_handle, "", 0, "")||
631 !read_env("LDAP_EMAILMAP_MAIL",
632 &ldap->emailmap_handle_lookup, "", 0, ""))
633 return (0);
634
635
636 for (pass=0; pass<2; pass++)
637 {
638 if (pass)
639 {
640 if ((ldap->auxnames=malloc((i+1)*sizeof(char *)))
641 == NULL ||
642 (ldap->auxoptions=malloc((i+1)*sizeof(char *)))
643 == NULL)
644 {
645 perror("CRIT: authldap: malloc failed");
646 if (ldap->auxnames)
647 ldap->auxnames[0]=0;
648 return 0;
649 }
650 }
651 i=0;
652
653 if (pass)
654 {
655 ldap->auxnames[0]=NULL;
656 ldap->auxoptions[0]=NULL;
657 }
658
659 if (!read_env("LDAP_AUXOPTIONS", &p, "", 0, NULL)
660 || p == NULL || *p == 0)
661 p=NULL;
662
663 while (p && *p)
664 {
665 size_t n;
666
667 if (*p == ',')
668 {
669 ++p;
670 continue;
671 }
672
673 for (n=0; p[n] && p[n] != ',' && p[n] != '='; n++)
674 ;
675
676 if (pass)
677 {
678 if ((ldap->auxoptions[i]=malloc(n+1)) == NULL)
679 {
680 perror("CRIT: authldap: malloc failed");
681 return 0;
682 }
683
684 memcpy(ldap->auxoptions[i], p, n);
685 ldap->auxoptions[i][n]=0;
686 ldap->auxoptions[i+1]=NULL;
687 }
688
689 p += n;
690
691 if (*p == '=') ++p;
692
693 for (n=0; p[n] && p[n] != ','; n++)
694 ;
695
696 if (pass)
697 {
698 if (n == 0)
699 {
700 if ((ldap->auxnames[i]=
701 strdup(ldap->auxoptions[i]))
702 == NULL)
703 {
704 perror("CRIT: authldap: malloc failed");
705 return 0;
706 }
707 }
708 else if ((ldap->auxnames[i]=malloc(n+1)) == NULL)
709 {
710 perror("CRIT: authldap: malloc failed");
711 return 0;
712 }
713 else
714 {
715 memcpy(ldap->auxnames[i], p, n);
716 ldap->auxnames[i][n]=0;
717 ldap->auxnames[i+1]=NULL;
718 }
719 }
720 p += n;
721 ++i;
722 }
723 }
724
725 if ((ldap->attrlist=malloc((i+20)*sizeof(const char *))) == NULL)
726 {
727 perror("CRIT: authldap: malloc failed");
728 return 0;
729 }
730
731 return 1;
732}
733
734static void get_error(LDAP *ld, LDAPMessage *entry,
735 const char *func,
736 const char *attribut)
737{
738#if HAVE_LDAP_PARSE_RESULT
739
740 int errcode;
741 char *nmatched;
742 char *errmsg;
743
744
745 if (ldap_parse_result(ld, entry, &errcode, &nmatched,
746 &errmsg, NULL, NULL, 0)
747 != LDAP_SUCCESS)
748 {
749 DPRINTF("ldap_parseresult failed");
750 }
751 else
752 {
753 if (errcode && errcode != LDAP_DECODING_ERROR &&
754 errcode != LDAP_NO_RESULTS_RETURNED)
755 {
756 DPRINTF("get_values attribute %s: %s",
757 attribut,
758 errmsg ? errmsg:"unknown error");
759 }
760
761 if (errmsg)
762 ldap_memfree(errmsg);
763 if (nmatched)
764 ldap_memfree(nmatched);
765 }
766#else
767#if HAVE_LDAP_RESULT2ERROR
768 int ld_errno = ldap_result2error(ld,entry,0);
769 if (ld_errno && ld_errno != LDAP_DECODING_ERROR
770 && ld_errno != LDAP_NO_RESULTS_RETURNED)
771 {
772 DPRINTF("get_values attribute %s: %s", attribut,
773 ldap_err2string(ld_errno));
774 }
775#else
776 if (ld->ld_errno != LDAP_DECODING_ERROR
777 && ld->ld_errno != LDAP_NO_RESULTS_RETURNED)
778 {
779 DPRINTF("get_values attribute %s: %s", attribut,
780 ldap_err2string(ld->ld_errno));
781 }
782#endif
783#endif
784}
785
786static char **get_values(LDAP *ld, LDAPMessage *entry, const char *attribut)
787{
788 char ** values;
789 values=l_get_values(ld,entry, (char *)attribut);
790
791 if (values==NULL)
792 {
793 get_error(ld, entry, "get_values", attribut);
794 }
795
796 return values;
797}
798
799
800
801/*
802 * Function: copy_value
803 * Copy value from a LDAP attribute to $copy
804 * INPUT:
805 * $ld: the connection with the LDAP server
806 * $entry: the entry who contains attributes
807 * $attribut: this attribut
808 * $copy: where data can go
809 * OUTPUT:
810 * void
811 */
812static void copy_value(LDAP *ld, LDAPMessage *entry, const char *attribut,
813 char **copy, const char *username)
814{
815 char ** values;
816 values=l_get_values(ld,entry, attribut);
817
818 if (values==NULL)
819 {
820 get_error(ld, entry, "copy_value ", attribut);
821 *copy=NULL;
822 return;
823 }
824 /* We accept only attribute with one value */
825 else if (l_count_values(values)>1)
826 {
827 *copy=strdup(values[0]);
828 fprintf(stderr, "WARN: authldaplib: duplicate attribute %s for %s\n",
829 attribut,
830 username);
831 *copy=NULL;
832 }
833 /* We accept only attribute with one value */
834 else if (l_count_values(values)!=1)
835 {
836 *copy=NULL;
837 }
838 else
839 {
840 *copy=strdup(values[0]);
841 }
842#if DEBUG_LDAP
843 DPRINTF("copy_value %s: %s",attribut,values[0]);
844#endif
845 l_value_free(values);
846}
847
848static struct ldap_info my_ldap;
849static LDAP *my_ldap_fp=0;
850static LDAP *bindp=0; /* for checking passwords with AUTHBIND */
851
852void authldapclose()
853{
854 if (my_ldap_fp)
855 {
856 l_unbind(my_ldap_fp);
857 my_ldap_fp=0;
858 }
859 if (bindp)
860 {
861 l_unbind(bindp);
862 bindp=0;
863 }
864}
865
866static int ldaperror(int rc)
867{
868#ifdef OPENLDAPV2
869 if (rc && !LDAP_NAME_ERROR(rc))
870#else
871 if (rc && !NAME_ERROR(rc))
872#endif
873 {
874 /* If there was a protocol error, close the connection */
875 authldapclose();
876 ldapconnfailure();
877 }
878 return (rc);
879}
880
881/* This function takes a ldap connection and
882 * tries to enable TLS on it.
883*/
884static int enable_tls_on(LDAP *conn) {
885#if HAVE_LDAP_TLS
886 int version;
887 int ldrc;
888
889 if (ldaperror(ldrc=ldap_get_option (conn,
890 LDAP_OPT_PROTOCOL_VERSION,
891 &version))
892 != LDAP_SUCCESS)
893 {
894 const char *s=ldap_err2string(ldrc);
895
896 err("ldap_get_option failed: %s", s);
897 return (-1);
898 }
899
900 if (version < LDAP_VERSION3)
901 {
902 version = LDAP_VERSION3;
903 (void)ldap_set_option (conn,
904 LDAP_OPT_PROTOCOL_VERSION,
905 &version);
906 }
907
908 if (ldaperror(ldrc=ldap_start_tls_s(conn, NULL, NULL))
909 != LDAP_SUCCESS)
910 {
911 const char *s=ldap_err2string(ldrc);
912
913 err("ldap_start_tls_s failed: %s", s);
914 return (-1);
915 }
916 return 0;
917#else
918 err("authldaplib: TLS not available");
919 return (-1);
920#endif
921}
922
923static LDAP *ldapconnect()
924{
925LDAP *p=NULL;
926
927#if DEBUG_LDAP
928 DPRINTF("URI: %s",my_ldap.uri);
929 DPRINTF("UID: %d",my_ldap.uid);
930 DPRINTF("GID: %d",my_ldap.gid);
931#endif
932
933 if (ldapconncheck())
934 {
935 DPRINTF("authldaplib: timing out after failed connection");
936 return (NULL);
937 }
938
939 ldap_initialize(&p, my_ldap.uri);
940
941 if (p==NULL)
942 {
943 err("cannot connect to LDAP server (%s): %s",
944 my_ldap.uri, strerror(errno));
945 ldapconnfailure();
946 }
947#ifdef LDAP_OPT_NETWORK_TIMEOUT
948 if (my_ldap.timeout > 0)
949 ldap_set_option (p, LDAP_OPT_NETWORK_TIMEOUT, &my_ldap.timeout);
950#endif
951#if DEBUG_LDAP
952 DPRINTF("ldapconnect end");
953#endif
954 return (p);
955}
956
957static int ldapopen()
958{
959int ldrc;
960
961 if (my_ldap_fp) return (0);
962
963 if (authldap_read_config(&my_ldap) == 0)
964 {
965 err("authldaplib: error in LDAP configuration file, aborting");
966 return (1);
967 }
968
969 my_ldap_fp=ldapconnect();
970
971 if (!my_ldap_fp)
972 {
973 return (1);
974 }
975
976#ifdef LDAP_OPT_PROTOCOL_VERSION
977
978 /* Set protocol version if selected */
979 if (my_ldap.protocol_version &&
980 ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_PROTOCOL_VERSION,
981 (void *) & my_ldap.protocol_version)) != LDAP_SUCCESS)
982 {
983 const char *s=ldap_err2string(ldrc);
984
985 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
986 my_ldap.protocol_version, s);
987 authldapclose();
988 ldapconnfailure();
989 return (-1);
990 }
991 if (my_ldap.protocol_version)
992 {
993 DPRINTF("selected ldap protocol version %d", my_ldap.protocol_version);
994 }
995#endif
996
997 if (my_ldap.tls && enable_tls_on(my_ldap_fp))
998 {
999 authldapclose();
1000 ldapconnfailure();
1001 return (-1);
1002 }
1003
1004#ifdef LDAP_OPT_DEREF
1005
1006 /* Set dereferencing mode */
1007 if (ldaperror(ldrc = ldap_set_option(my_ldap_fp, LDAP_OPT_DEREF,
1008 (void *) & my_ldap.deref)) != LDAP_SUCCESS)
b0322a85 1009 {
d9898ee8 1010 const char *s=ldap_err2string(ldrc);
1011
1012 err("ldap_set_option(DEREF) failed: %s", s);
1013 authldapclose();
1014 ldapconnfailure();
1015 return (-1);
b0322a85 1016 }
d9898ee8 1017#endif
1018
b0322a85
CE
1019 if(my_ldap.initbind)
1020 {
1021 /* Bind to server */
1022 if (courier_authdebug_login_level >= 2)
1023 {
1024 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
1025 my_ldap.binddn ? my_ldap.binddn : "<null>",
1026 my_ldap.bindpw ? my_ldap.bindpw : "<null>");
1027 }
1028 else
1029 {
1030 DPRINTF("binding to LDAP server as DN '%s'",
1031 my_ldap.binddn ? my_ldap.binddn : "<null>");
1032 }
1033
1034 if (ldaperror(ldrc = l_simple_bind_s(my_ldap_fp,
1035 my_ldap.binddn,
1036 my_ldap.bindpw))
1037 != LDAP_SUCCESS)
1038 {
1039 const char *s=ldap_err2string(ldrc);
1040
1041 err("ldap_simple_bind_s failed: %s", s);
1042 authldapclose();
1043 ldapconnfailure();
1044 return (-1);
1045 }
1046 }
d9898ee8 1047 return (0);
1048}
1049
1050static int auth_ldap_do(const char *, const char *, const char *,
1051 int (*)(struct authinfo *, void *),
1052 void *arg, const char *);
1053
1054int auth_ldap_changepw(const char *dummy, const char *user,
1055 const char *pass,
1056 const char *newpass)
1057{
1058 return auth_ldap_do("authlib", user, pass, NULL, NULL, newpass);
1059}
1060
1061/*
1062 * Function: authldapcommon
1063 * Get information from the LDAP server ($ldap) for this $user
1064 * INPUT:
1065 * $user: the login name
1066 * $pass: the login password (NULL if we don't want to check the pw)
1067 * callback - callback function with filled in authentication info
1068 * arg - extra argument for the callback function.
1069 * OUTPUT:
1070 * < 0 - authentication failure
1071 * > 0 - temporary failure
1072 * else return code from the callback function.
1073 */
1074
1075int authldapcommon(const char *service,
1076 const char *user, const char *pass,
1077 int (*callback)(struct authinfo *, void *),
1078 void *arg)
1079{
1080 return (auth_ldap_do(service, user, pass, callback, arg, NULL));
1081}
1082
1083static int auth_ldap_do2(const char *service,
1084 const char *user, const char *pass,
1085 int (*callback)(struct authinfo *, void *),
1086 void *arg, const char *newpass);
1087
d9898ee8 1088static int auth_ldap_retry(const char *service,
1089 const char *user, const char *pass,
1090 int (*callback)(struct authinfo *, void *),
1091 void *arg, const char *newpass);
1092
1093static int auth_ldap_do(const char *service,
1094 const char *user, const char *pass,
1095 int (*callback)(struct authinfo *, void *),
1096 void *arg, const char *newpass)
1097{
1098 int rc=auth_ldap_retry(service, user, pass, callback, arg, newpass);
1099
1100 if (rc > 0)
1101 rc=auth_ldap_retry(service, user, pass, callback, arg,
1102 newpass);
1103
1104 return rc;
1105}
1106
1107static int auth_ldap_retry(const char *service,
1108 const char *user, const char *pass,
1109 int (*callback)(struct authinfo *, void *),
1110 void *arg, const char *newpass)
1111{
1112 char *q;
1113 int i;
1114
8d138742 1115 q=courier_auth_ldap_escape(user);
d9898ee8 1116
1117 if (!q)
8d138742
CE
1118 {
1119 perror("malloc");
1120 return 1;
1121 }
d9898ee8 1122
1123 i=auth_ldap_do2(service, q, pass, callback, arg, newpass);
1124 free(q);
1125 return (i);
1126}
1127
1128
1129static int auth_ldap_do3(const char *service,
1130 const char *attrname,
1131 const char *user, const char *pass,
1132 int (*callback)(struct authinfo *, void *),
1133 void *arg, const char *newpass, const char *authaddr);
1134
1135static char *emailmap_get_search_string(const char *str, const char *email);
1136
1137static int auth_ldap_do2(const char *service,
1138 const char *user, const char *pass,
1139 int (*callback)(struct authinfo *, void *),
1140 void *arg, const char *newpass)
1141{
1142 char *srch;
1143 struct timeval tv;
1144 const char *attributes[2];
1145 LDAPMessage *result, *entry;
1146 int cnt;
1147 char *v;
1148 const char *aname;
1149
b0322a85 1150 if (ldapopen()) return (-1);
d9898ee8 1151
1152 if (my_ldap.emailmap[0] == 0 || strchr(user, '@') == NULL)
1153 return (auth_ldap_do3(service, my_ldap.mail,
1154 user, pass, callback, arg, newpass,
1155 user));
1156 /* Mapping is not enabled */
1157
1158 srch=emailmap_get_search_string(my_ldap.emailmap, user);
1159
1160 if (!srch)
1161 {
1162 perror("CRIT: authldaplib: malloc");
1163 exit(1);
1164 }
1165 DPRINTF("using emailmap search: %s", srch);
1166
1167 tv.tv_sec=my_ldap.timeout;
1168 tv.tv_usec=0;
1169
1170 attributes[0]=my_ldap.emailmap_handle;
1171
1172 if (!attributes[0][0])
1173 attributes[0]="handle";
1174 attributes[1]=NULL;
1175
1176 if (ldaperror(l_search_st(my_ldap_fp,
1177 (char *)(my_ldap.emailmap_basedn[0] ?
1178 my_ldap.emailmap_basedn
1179 :my_ldap.basedn),
1180 LDAP_SCOPE_SUBTREE,
1181 srch, (char **)attributes, 0,
1182 &tv, &result))
1183 != LDAP_SUCCESS)
1184 {
1185 free(srch);
1186
1187 DPRINTF("ldap_search_st failed");
1188 if (my_ldap_fp) return (-1);
1189 return (1);
1190 }
1191
1192 if ((cnt=ldap_count_entries(my_ldap_fp, result)) != 1)
1193 {
d9898ee8 1194 if (cnt)
1195 err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1196 cnt, srch);
8d138742 1197 free(srch);
d9898ee8 1198 ldap_msgfree(result);
1199 return -1;
1200 }
1201 free(srch);
1202
1203 entry=ldap_first_entry(my_ldap_fp, result);
1204
1205 if (!entry)
1206 {
1207 ldap_msgfree(result);
1208
1209 err("authldap: unexpected NULL from ldap_first_entry");
1210 return -1;
1211 }
1212
1213 copy_value(my_ldap_fp, entry, attributes[0], &v, user);
1214
1215 if (!v)
1216 {
1217 DPRINTF("emailmap: empty attribute");
1218 ldap_msgfree(result);
1219 return (-1);
1220 }
1221
1222 aname=my_ldap.emailmap_handle_lookup;
1223 if (aname[0] == 0)
1224 aname=my_ldap.mail;
1225
1226 DPRINTF("emailmap results: aname=%s, handle=%s", aname, v);
1227
1228 cnt=auth_ldap_do3(service,
1229 aname, v, pass, callback, arg, newpass, user);
1230
1231 ldap_msgfree(result);
1232 free(v);
1233 return (cnt);
1234}
1235
1236static int auth_ldap_do3(const char *service,
1237 const char *attrname,
1238 const char *user, const char *pass,
1239 int (*callback)(struct authinfo *, void *),
1240 void *arg, const char *newpass,
1241 const char *authaddr)
1242{
1243 char *newpass_crypt=0;
1244 const char *attributes[10];
1245 struct timeval timeout;
1246
1247 LDAPMessage *result;
1248 LDAPMessage *entry;
1249 char *filter, *dn;
1250 int i, j;
1251
1252 struct authinfo auth;
1253 char *homeDir=0;
1254 char *mailDir=0;
1255 char *userPassword=0;
1256 char *cryptPassword=0;
1257 char *options=0;
1258 char *cn=0;
1259 uid_t au;
1260 gid_t ag;
1261 int rc;
1262 char *quota=0;
1263 int additionalFilter = 0;
1264 int hasAdditionalFilter = 0;
1265
1266 hasAdditionalFilter = my_ldap.filter != 0;
1267
1268 memset(&auth, 0, sizeof(auth));
1269
1270 if (hasAdditionalFilter)
1271 {
1272 /* To add the additional filter, we need to add on the
1273 * additional size for "(&)" and the other filter. So
1274 * filter+3
1275 */
1276 additionalFilter = strlen(my_ldap.filter) + 3;
1277 }
1278
1279 if ((filter=malloc(additionalFilter+strlen(attrname)+strlen(user)+
1280 (my_ldap.domain ? strlen(my_ldap.domain):0)+
1281 sizeof ("(=@)"))) == 0)
1282 {
1283 perror("malloc");
1284 return 1;
1285 }
1286 strcpy(filter, "\0");
1287
1288 if (hasAdditionalFilter)
1289 {
1290 strcat(filter, "(&");
1291 strcat(filter, my_ldap.filter);
1292 }
1293
1294 strcat(strcat(strcat(strcat(filter, "("), attrname), "="), user);
1295 if ( my_ldap.domain && my_ldap.domain[0] && strchr(user, '@') == 0 )
1296 strcat(strcat(filter, "@"), my_ldap.domain);
1297 strcat(filter, ")");
1298
1299 if (hasAdditionalFilter)
1300 {
1301 strcat(filter, ")");
1302 }
1303
1304 DPRINTF("using search filter: %s", filter);
1305
1306 timeout.tv_sec=my_ldap.timeout;
1307 timeout.tv_usec=0;
1308
1309 read_env("LDAP_HOMEDIR", &attributes[0], "", 0, "homeDir");
1310 read_env(service && strcmp(service, "courier") == 0
1311 ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR",
1312 &attributes[1], "", 0, 0);
1313 read_env("LDAP_FULLNAME", &attributes[2], "", 0, "cn");
1314 read_env("LDAP_CLEARPW", &attributes[3], "", 0, 0);
1315 read_env("LDAP_CRYPTPW", &attributes[4], "", 0, 0);
1316 read_env("LDAP_UID", &attributes[5], "", 0, 0);
1317 read_env("LDAP_GID", &attributes[6], "", 0, 0);
1318 attributes[7]=my_ldap.mail;
1319 read_env("LDAP_MAILDIRQUOTA", &attributes[8], "", 0, 0);
1320
1321 j=0;
1322 for (i=0; i<9; i++)
1323 {
1324 if (attributes[i])
1325 my_ldap.attrlist[j++]=attributes[i];
1326 }
1327
1328 for (i=0; my_ldap.auxoptions[i]; i++)
1329 my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
1330
1331 my_ldap.attrlist[j]=0;
1332
1333 if (ldaperror(l_search_st(my_ldap_fp,
1334 (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
1335 filter, (char **)my_ldap.attrlist, 0,
1336 &timeout, &result))
1337 != LDAP_SUCCESS)
1338 {
1339 DPRINTF("ldap_search_st() failed");
1340 free(filter);
1341
1342 if (my_ldap_fp) return (-1);
1343 return (1);
1344 }
1345
1346 free(filter);
1347
1348 /* If we are more than one result, reject */
1349 if (ldap_count_entries(my_ldap_fp,result)!=1)
1350 {
1351 DPRINTF("number of entries returned: %d (but we need exactly 1)",
1352 ldap_count_entries(my_ldap_fp,result));
1353 ldap_msgfree(result);
1354 return -1;
1355 }
1356
1357 dn = ldap_get_dn(my_ldap_fp, result);
1358
1359 DPRINTF("one entry returned, DN: %s", dn ? dn : "<null>");
1360
1361 if (dn == NULL)
1362 {
1363 DPRINTF("ldap_get_dn failed");
1364 return -1;
1365 }
1366
1367 /* Get the pointer on this result */
1368 entry=ldap_first_entry(my_ldap_fp,result);
1369 if (entry==NULL)
1370 {
1371 DPRINTF("ldap_first_entry failed");
1372 free(dn);
1373 return -1;
1374 }
1375
1376#if DEBUG_LDAP
1377 DPRINTF("after ldap_first_entry");
1378#endif
1379
1380 /* print all the raw attributes */
1381 if (courier_authdebug_login_level >= 2)
1382 {
1383 char *attr;
1384 BerElement *berptr = 0;
1385
1386 attr = ldap_first_attribute(my_ldap_fp, entry, &berptr);
1387 if (attr)
1388 {
1389 DPRINTF("raw ldap entry returned:");
1390 }
1391
1392 while (attr)
1393 {
1394 char **av, **ap;
1395
1396 av = l_get_values(my_ldap_fp, entry, attr);
1397 ap = av;
1398 if (av)
1399 {
1400 while(*ap)
1401 {
1402 DPRINTF("| %s: %s", attr, *ap);
1403 ap++;
1404 }
1405 l_value_free(av);
1406 }
1407 ldap_memfree(attr);
1408 attr = ldap_next_attribute(my_ldap_fp, entry, berptr);
1409 }
1410
1411 ber_free(berptr, 0);
1412 }
1413
1414 /* Copy the directory and the password into struct */
1415 copy_value(my_ldap_fp,entry,attributes[0],&homeDir, user);
1416 if (attributes[1])
1417 copy_value(my_ldap_fp,entry,attributes[1],&mailDir, user);
1418 copy_value(my_ldap_fp,entry,attributes[2],&cn, user);
1419 if (attributes[3])
1420 copy_value(my_ldap_fp,entry,attributes[3],&userPassword, user);
1421 if (attributes[4])
1422 copy_value(my_ldap_fp,entry,attributes[4],&cryptPassword, user);
1423
1424 au=my_ldap.uid;
1425 ag=my_ldap.gid;
1426 if (attributes[5])
1427 {
1428 char *p=0;
1429 unsigned long n;
1430
1431 copy_value(my_ldap_fp, entry, attributes[5], &p, user);
1432 if (p) {
1433 if (sscanf(p, "%lu", &n) > 0)
1434 au= (uid_t)n;
1435 free(p);
1436 }
1437#if DEBUG_LDAP
1438 DPRINTF("au= %d",au);
1439#endif
1440 }
1441
1442 if (attributes[6])
1443 {
1444 char *p=0;
1445 unsigned long n;
1446
1447 copy_value(my_ldap_fp, entry, attributes[6], &p, user);
1448 if (p) {
1449 if (sscanf(p, "%lu", &n) > 0)
1450 ag= (gid_t)n;
1451 free(p);
1452 }
1453#if DEBUG_LDAP
1454 DPRINTF("ag= %d",ag);
1455#endif
1456 }
1457
1458 if (attributes[8])
1459 copy_value(my_ldap_fp,entry,attributes[8],&quota, user);
1460
1461 if (homeDir != 0 && my_ldap.mailroot != 0 && *my_ldap.mailroot)
1462 {
1463 char *new_mailroot=malloc(strlen(homeDir)+
1464 strlen(my_ldap.mailroot)+2);
1465
1466 if (!new_mailroot)
1467 {
1468 perror("CRIT: authldap: malloc failed");
1469 rc= -1;
1470 }
1471 else
1472 {
1473 strcat(strcat(strcpy(new_mailroot, my_ldap.mailroot),
1474 "/"), homeDir);
1475 free(homeDir);
1476 homeDir=new_mailroot;
1477 }
1478 }
1479
1480 j=1;
1481
1482 for (i=0; my_ldap.auxoptions[i]; i++)
1483 {
1484 char *val;
1485
1486 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i], &val,
1487 user);
1488
1489 if (!val)
1490 continue;
1491
1492 j += 2 + strlen(my_ldap.auxnames[i]) +
1493 strlen(val);
1494 free(val);
1495 }
1496
1497 options=malloc(j);
1498
1499 if (!options)
1500 {
1501 perror("CRIT: authldap: malloc failed");
1502 rc= -1;
1503 }
1504 else
1505 {
1506 *options=0;
1507
1508 for (i=0; my_ldap.auxoptions[i]; i++)
1509 {
1510 char *val;
1511
1512 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
1513 &val,
1514 user);
1515
1516 if (!val)
1517 continue;
1518
1519 if (*options)
1520 strcat(options, ",");
1521 strcat(options, my_ldap.auxnames[i]);
1522 strcat(options, "=");
1523 strcat(options, val);
1524 free(val);
1525 }
1526 }
1527
1528
1529 auth.sysuserid= &au;
1530 auth.sysgroupid= ag;
1531 auth.homedir=homeDir;
1532 auth.address=authaddr;
1533 auth.fullname=cn;
1534 auth.maildir=mailDir;
1535 auth.clearpasswd=userPassword;
1536 auth.passwd=cryptPassword;
1537 auth.quota=quota;
1538 auth.options=options && *options ? options:NULL;
1539
1540 if (homeDir == 0)
1541 auth.homedir="";
1542
1543 rc=0;
1544
1545 if (au == 0 || ag == 0)
1546 {
1547 err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1548 user, au, ag);
1549 rc= 1;
1550 }
1551
1552 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth,
1553 userPassword, cryptPassword);
1554
1555 if (pass)
1556 {
1557 if (my_ldap.authbind)
1558 {
1559 if (!bindp)
1560 {
1561 bindp=ldapconnect();
1562
1563 if (!bindp)
1564 {
1565 DPRINTF("ldapconnect failed");
1566 rc=1;
1567 }
1568 else
1569#ifdef LDAP_OPT_PROTOCOL_VERSION
1570 /* Set protocol version */
1571 if (my_ldap.protocol_version &&
1572 ldap_set_option(bindp, LDAP_OPT_PROTOCOL_VERSION,
1573 (void *) & my_ldap.protocol_version) != LDAP_OPT_SUCCESS)
1574 {
1575 err("ldap_set_option(PROTOCOL_VERSION %d) failed",
1576 my_ldap.protocol_version);
1577 rc = 1;
1578 }
1579 else
1580#endif
1581 if(my_ldap.tls && enable_tls_on(bindp)) {
1582 err("authldaplib: LDAP_TLS enabled but I'm unable to start tls, check your config");
1583 rc = 1;
1584 }
1585 }
1586
1587 if (bindp)
1588 {
1589 if (rc == 0)
1590 {
1591 int ldrc;
1592 DPRINTF("rebinding with DN '%s' to validate password", dn);
1593 ldrc = l_simple_bind_s(bindp, dn, pass);
1594 switch (ldrc)
1595 {
1596 case LDAP_SUCCESS:
1597 DPRINTF("authentication bind successful");
1598 break;
1599 case LDAP_INVALID_CREDENTIALS:
1600 DPRINTF("authentication bind failed, invalid credentials");
1601 rc = -1;
1602 break;
1603 default:
1604 DPRINTF("authentication bind failed, some other problem: %s",
1605 ldap_err2string(ldrc));
1606 rc = 1;
1607 break;
1608 }
1609 }
1610 /* Drop the connection if there was a fatal
1611 error or if we are using historic LDAP v2,
1612 which didn't support rebinding on same conn */
1613 if (rc > 0 || my_ldap.protocol_version == 2)
1614 {
1615 l_unbind(bindp);
1616 bindp=0;
1617 }
1618 }
1619
1620 if (rc == 0 && newpass)
1621 {
1622 if ((newpass_crypt=authcryptpasswd(newpass,
1623 auth.passwd)
1624 ) == 0)
1625 rc= -1;
1626 }
1627 }
1628 else
1629 {
1630 if (auth.clearpasswd)
1631 {
1632 if (strcmp(pass,auth.clearpasswd))
1633 {
1634 if (courier_authdebug_login_level >= 2)
1635 {
1636 DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
1637 pass, auth.clearpasswd);
1638 }
1639 else
1640 {
1641 DPRINTF("supplied password does not match clearpasswd");
1642 }
1643 rc= -1;
1644 }
1645 }
1646 else
1647 {
1648 const char *p=auth.passwd;
1649
1650 if (!p)
1651 {
1652 DPRINTF("no password to compare against!");
1653 rc= -1;
1654 }
1655 else if (authcheckpassword(pass, p))
1656 rc= -1;
1657 }
1658
1659 if (rc == 0 && newpass && auth.passwd)
1660 {
1661 if ((newpass_crypt=authcryptpasswd(newpass,
1662 auth.passwd)
1663 ) == 0)
1664 rc= -1;
1665 }
1666 }
1667 }
1668
1669 if (rc == 0 && newpass)
1670 {
1671 LDAPMod *mods[3];
1672 int mod_index=0;
1673
1674 LDAPMod mod_clear, mod_crypt;
1675 char *mod_clear_vals[2], *mod_crypt_vals[2];
1676
1677 if (attributes[3])
1678 {
1679 mods[mod_index]= &mod_clear;
1680 mod_clear.mod_op=LDAP_MOD_REPLACE;
1681 mod_clear.mod_type=(char *)attributes[3];
1682 mod_clear.mod_values=mod_clear_vals;
1683
1684 mod_clear_vals[0]=(char *)newpass;
1685 mod_clear_vals[1]=NULL;
1686 ++mod_index;
1687 }
1688
1689 if (attributes[4] && newpass_crypt)
1690 {
1691 mods[mod_index]= &mod_crypt;
1692 mod_crypt.mod_op=LDAP_MOD_REPLACE;
1693 mod_crypt.mod_type=(char *)attributes[4];
1694 mod_crypt.mod_values=mod_crypt_vals;
1695
1696 mod_crypt_vals[0]=newpass_crypt;
1697 mod_crypt_vals[1]=NULL;
1698 ++mod_index;
1699 }
1700 if (mod_index == 0)
1701 rc= -1;
1702 else
1703 {
1704 int ld_errno;
1705 mods[mod_index]=0;
1706
1707 /* On a system which uses LDAP_AUTHBIND, we probably
1708 want to use the user's credentials (bindp) rather
1709 than the search credentials (my_ldap_fp) for
1710 performing the password update. (May not always be
1711 true, ideally it would be configurable) */
1712 ld_errno = l_modify_s(bindp? bindp:my_ldap_fp, dn, mods);
1713 if (ld_errno != LDAP_SUCCESS)
1714 {
1715 rc= -1;
1716 DPRINTF("LDAP modify failed: %s",
1717 ldap_err2string(ld_errno));
1718 }
1719 }
1720 }
1721
1722 if (newpass_crypt)
1723 free(newpass_crypt);
1724 free (dn);
1725#if DEBUG_LDAP
1726 DPRINTF("before callback rc=%d",rc);
1727#endif
1728
1729 if (rc == 0 && callback)
1730 {
1731 if (!auth.clearpasswd)
1732 auth.clearpasswd=pass;
1733 rc= (*callback)(&auth, arg);
1734#if DEBUG_LDAP
1735 DPRINTF("after callback rc=%d",rc);
1736#endif
1737 }
1738
1739 ldap_msgfree(result);
1740 if (options) free(options);
1741 if (homeDir) free(homeDir);
1742 if (mailDir) free(mailDir);
1743 if (userPassword) free(userPassword);
1744 if (cryptPassword) free(cryptPassword);
1745 if (cn) free(cn);
1746 if (quota) free(quota);
1747 return (rc);
1748}
1749
d9898ee8 1750/**
1751 ** Create an emailmap search string. I'm going to wrap this into an external
1752 ** variable, so I'll use generic coding here.
1753 */
1754
1755struct varlist {
1756 const char *varname;
1757 int varname_len;
1758 const char *varvalue;
1759 int varvalue_len;
1760} ;
1761
1762static char *var_expand(const char *, const struct varlist *);
1763
1764static char *emailmap_get_search_string(const char *str, const char *email)
1765{
1766 struct varlist vl[3];
1767 const char *realmptr=strrchr(email, '@');/* Guaranteed nonNULL */
1768
1769 static const char userid[]="user";
1770 static const char realm[]="realm";
1771
1772 vl[0].varname=userid;
1773 vl[0].varname_len=sizeof(userid)-1;
1774 vl[0].varvalue=email;
1775 vl[0].varvalue_len=realmptr - email;
1776 vl[1].varname=realm;
1777 vl[1].varname_len=sizeof(realm)-1;
1778 vl[1].varvalue=realmptr+1;
1779 vl[1].varvalue_len=strlen(vl[1].varvalue);
1780 vl[2].varname=NULL;
1781
1782 return (var_expand(str, vl));
1783}
1784
1785static char *var_expand(const char *str, const struct varlist *vl)
1786{
1787 const char *p;
1788 int cnt;
1789 int pass;
1790 char *q, *r;
1791
1792 cnt=0;
1793 q=NULL;
1794
1795 /*
1796 ** Pass 1 - count expanded string length, allocate buffer,
1797 ** Pass 2 - generate the string.
1798 */
1799
1800 for (pass=0; pass<2; pass++)
1801 {
1802 if (pass)
1803 {
1804 if ((q=malloc(cnt)) == NULL)
1805 return (NULL);
1806 }
1807 r=q;
1808 cnt=1;
1809
1810 p=str;
1811
1812 while (*p)
1813 {
1814 if (*p == '@')
1815 {
1816 int j;
1817
1818 for (j=0; vl[j].varname; j++)
1819 {
1820 if (memcmp(vl[j].varname, p+1,
1821 vl[j].varname_len) == 0
1822 && p[vl[j].varname_len+1] == '@')
1823 break;
1824 }
1825
1826 if (vl[j].varname)
1827 {
1828 p += vl[j].varname_len+2;
1829
1830 if (r)
1831 {
1832 memcpy(r, vl[j].varvalue,
1833 vl[j].varvalue_len);
1834 r += vl[j].varvalue_len;
1835 }
1836 cnt += vl[j].varvalue_len;
1837 continue;
1838 }
1839 }
1840
1841 if (r)
1842 *r++ = *p;
1843 ++p;
1844 ++cnt;
1845 }
1846 if (r)
1847 *r=0;
1848 }
1849
1850 return (q);
1851}
1852
1853void auth_ldap_enumerate( void(*cb_func)(const char *name,
1854 uid_t uid,
1855 gid_t gid,
1856 const char *homedir,
1857 const char *maildir,
1858 const char *options,
1859 void *void_arg),
1860 void *void_arg)
1861{
1862 const char *attributes[5];
1863
1864 int i, j;
1865 int msgid;
1866
b0322a85
CE
1867 if (ldapopen())
1868 {
1869 (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
1870 return;
1871 }
d9898ee8 1872
1873 read_env("LDAP_MAIL", &attributes[0], "", 0, "mail");
1874 read_env("LDAP_UID", &attributes[1], "", 0, 0);
1875 read_env("LDAP_GID", &attributes[2], "", 0, 0);
1876 read_env("LDAP_HOMEDIR", &attributes[3], "", 0, "homeDir");
1877 read_env("LDAP_MAILDIR", &attributes[4], "", 0, 0);
1878
1879 j=0;
1880 for (i=0; i<5; i++)
1881 {
1882 if (attributes[i])
1883 my_ldap.attrlist[j++]=attributes[i];
1884 }
1885
1886 for (i=0; my_ldap.auxoptions[i]; i++)
1887 my_ldap.attrlist[j++]=my_ldap.auxoptions[i];
1888
1889 my_ldap.attrlist[j]=0;
1890
1891 DPRINTF("ldap_search: basedn='%s', filter='%s'",
1892 my_ldap.basedn, my_ldap.enumerate_filter);
1893 if ((msgid = l_search(my_ldap_fp, (char *)my_ldap.basedn,LDAP_SCOPE_SUBTREE,
1894 my_ldap.enumerate_filter,
1895 (char **)my_ldap.attrlist, 0)) < 0)
1896 {
1897 DPRINTF("ldap_search failed");
1898 return;
1899 }
1900
1901 while(1) /* process results as they come in */
1902 {
1903 struct timeval timeout;
1904 LDAPMessage *result;
1905 LDAPMessage *entry;
1906 int ldrc;
1907
1908 timeout.tv_sec=my_ldap.timeout;
1909 timeout.tv_usec=0;
1910 ldrc = ldap_result(my_ldap_fp, msgid, 0, &timeout, &result);
1911 switch (ldrc)
1912 {
1913 case -1:
1914 DPRINTF("error in ldap_result");
1915 ldap_msgfree(result);
1916 return;
1917 case 0:
1918 DPRINTF("timeout waiting for search result");
1919 ldap_msgfree(result);
1920 return;
1921 case LDAP_RES_SEARCH_ENTRY:
1922 break; /* deal with below */
1923 case LDAP_RES_SEARCH_RESULT:
1924 if (ldap_parse_result(my_ldap_fp, result, &ldrc,
1925 NULL, NULL, NULL, NULL, 0) != LDAP_SUCCESS)
1926 {
1927 DPRINTF("ldap_parse_result failed");
1928 ldap_msgfree(result);
1929 return;
1930 }
1931 ldap_msgfree(result);
1932 if (ldrc != LDAP_SUCCESS)
1933 {
1934 DPRINTF("ldap search failure result: %s",
1935 ldap_err2string(ldrc));
1936 return;
1937 }
1938 /* Search successfully completed */
1939 (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
1940 return;
1941 default:
1942 DPRINTF("ldap result type 0x%02X ignored", ldrc);
1943 ldap_msgfree(result);
1944 continue;
1945 }
1946
1947 entry = ldap_first_entry(my_ldap_fp, result);
1948 while (entry)
1949 {
1950 char **names = get_values(my_ldap_fp, entry, attributes[0]);
1951 int n;
1952
1953 if (names == NULL)
1954 {
1955 entry = ldap_next_entry(my_ldap_fp, entry);
1956 continue;
1957 }
1958
1959 n=l_count_values(names);
1960 if (n > 0)
1961 {
1962 const char *name = names[0] ? names[0] : "<null>";
1963 int i,j;
1964 char *uid_s=NULL;
1965 char *gid_s=NULL;
1966 char *homedir;
1967 char *maildir;
1968 char *options;
1969 uid_t uid=my_ldap.uid;
1970 gid_t gid=my_ldap.gid;
1971
1972 if (attributes[1])
1973 {
1974 copy_value(my_ldap_fp, entry, attributes[1],
1975 &uid_s,
1976 name);
1977 }
1978
1979 if (attributes[2])
1980 {
1981 copy_value(my_ldap_fp, entry, attributes[2],
1982 &gid_s, name);
1983 }
1984
1985 copy_value(my_ldap_fp, entry, attributes[3],
1986 &homedir, name);
1987 copy_value(my_ldap_fp, entry, attributes[4],
1988 &maildir, name);
1989
1990 if (uid_s)
1991 uid=atol(uid_s);
1992 if (gid_s)
1993 gid=atol(gid_s);
1994
1995 j=1;
1996
1997 for (i=0; my_ldap.auxoptions[i]; i++)
1998 {
1999 char *val;
2000
2001 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
2002 &val, name);
2003
2004 if (!val)
2005 continue;
2006
2007 j += 2 + strlen(my_ldap.auxnames[i]) +
2008 strlen(val);
2009 free(val);
2010 }
2011
2012 options=malloc(j);
2013
2014 if (!options)
2015 {
8d138742 2016 l_value_free(names);
d9898ee8 2017 perror("CRIT: auth_ldap_enumerate: malloc failed");
2018 return;
2019 }
2020 *options=0;
2021
2022 for (i=0; my_ldap.auxoptions[i]; i++)
2023 {
2024 char *val;
2025
2026 copy_value(my_ldap_fp, entry, my_ldap.auxoptions[i],
2027 &val, name);
2028
2029 if (!val)
2030 continue;
2031
2032 if (*options)
2033 strcat(options, ",");
2034 strcat(options, my_ldap.auxnames[i]);
2035 strcat(options, "=");
2036 strcat(options, val);
2037 free(val);
2038 }
2039
2040 for (j = 0; j < n; j++)
2041 {
2042 name=names[j];
2043
2044 if (name && homedir)
2045 (*cb_func)(name, uid, gid, homedir,
2046 maildir, options, void_arg);
2047 }
2048
2049 if (uid_s)
2050 free(uid_s);
2051 if (gid_s)
2052 free(gid_s);
2053 if (homedir)
2054 free(homedir);
2055 if (maildir)
2056 free(maildir);
2057 if (options)
2058 free(options);
2059 }
2060 l_value_free(names);
2061
2062 entry = ldap_next_entry(my_ldap_fp, entry);
2063 }
2064
2065 ldap_msgfree(result);
2066 }
2067}