6 * Copyright 1999 Luc Saillard <luc.saillard@alcove.fr>.
8 * This module use a server LDAP to authenticate user.
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.
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.
20 * See the GNU General Public License for more details.
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
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
25 * Boston, MA 02110-1301, USA.
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).
40 Modified 01/21/2000 James Golovich <james@wwnet.net>
42 1. If LDAP_AUTHBIND is set in the config file, then the ldap server will
43 handle passwords via authenticated binds, instead of checking these
45 2. Changed paramaters for authldap_get to include pass.
50 Modified 12/31/99 Sam Varshavchik:
52 1. read_env reads from a configuration file, instead of the environment
53 2. read_config appropriately modified.
54 3. If 'user' contains the @ character, domain from config is NOT appended.
55 4. added 'homeDir' attribute. Use 'homeDir' instead of mailDir, and put
57 5. read_config renamed to authldap_read_config
58 6. get_user_info renamed to authldap_get
59 7. Added authldap_free_config, to clean up all the allocated memory
60 (required for preauthldap).
61 8. Output LDAP attributes are defined in the configuration file as well.
62 9. Allow both plaintext and crypted passwords to be read from LDAP.
63 10. Added GLOB_UID GLOB_GID, as well as UID and GID params.
67 Rewrite to allow this code to be used in a long-running authentication daemon
68 (for Courier). authldap_get renamed to authldapcommon, will initialize and
69 maintain a persistent connection. Password checking moved entirely to
70 authldap.c. authldapclose() will unbind and close the connection.
72 connection gets closed and reopened automatically after a protocol error.
74 error return from authldapcommon will indicate whether this is a transient,
75 or a permanent failure.
77 authldap_free_config removed - no longer required.
82 #include "courier_auth_config.h"
100 #if LDAP_VENDOR_VERSION > 20000
105 #include <sys/time.h>
108 #include <sys/stat.h>
111 #include "authldap.h"
113 #include "authldaprc.h"
114 #include "courierauthdebug.h"
116 #define err courier_auth_err
122 #ifndef LDAP_OPT_SUCCESS
123 #define LDAP_OPT_SUCCESS LDAP_SUCCESS
126 static char **l_get_values(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
)
128 struct berval
**p
=ldap_get_values_len(ld
, entry
, attribut
);
135 n
=ldap_count_values_len(p
);
138 a
=malloc((n
+ 1) * sizeof(char *));
142 DPRINTF("malloc failed");
143 ldap_value_free_len(p
);
149 if ((a
[i
]=malloc(p
[i
]->bv_len
+1)) == NULL
)
151 DPRINTF("malloc failed");
157 ldap_value_free_len(p
);
161 memcpy(a
[i
], p
[i
]->bv_val
, p
[i
]->bv_len
);
162 a
[i
][p
[i
]->bv_len
]=0;
165 ldap_value_free_len(p
);
170 static void l_value_free(char **p
)
179 static int l_count_values(char **p
)
188 static int l_unbind(LDAP
*ld
)
190 return ldap_unbind_ext(ld
, NULL
, NULL
);
193 static int l_simple_bind_s(LDAP
*ld
,
199 cred
.bv_len
=passwd
? strlen(passwd
):0;
200 cred
.bv_val
=(char *)passwd
;
202 return ldap_sasl_bind_s(ld
, who
, NULL
, &cred
, NULL
, NULL
, NULL
);
205 static int l_search_st(LDAP
*ld
,
211 struct timeval
*timeout
,
214 return ldap_search_ext_s(ld
, base
, scope
, filter
, attrs
,
222 static int l_modify_s(LDAP
*ld
,
226 return ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
229 static int l_search(LDAP
*ld
,
242 if (ldap_search_ext(ld
, base
, scope
, filter
, attrs
, attrsonly
,
243 NULL
, NULL
, &tv
, 1000000, &msgid
) !=
258 const char *enumerate_filter
;
267 int protocol_version
;
270 const char *mailroot
;
274 const char **attrlist
;
276 /* Optional emailmap to handle */
278 const char *emailmap
;
279 const char *emailmap_basedn
;
280 const char *emailmap_handle
;
281 const char *emailmap_handle_lookup
;
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.
291 ** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
292 ** off this behavior (whenever OpenLDAP gets fixed).
295 static time_t ldapfailflag
=0;
297 static void ldapconnfailure()
299 const char *p
=getenv("LDAP_MEMORY_LEAK");
303 #ifdef LDAP_VENDOR_NAME
304 #ifdef LDAP_VENDOR_VERSION
305 #define DO_OPENLDAP_CHECK
309 #ifdef DO_OPENLDAP_CHECK
311 /* It's supposed to be fixed in 20019 */
313 if (strcmp(LDAP_VENDOR_NAME
, "OpenLDAP") == 0 &&
314 LDAP_VENDOR_VERSION
< 20019)
323 if (atoi(p
) && !ldapfailflag
)
330 static int ldapconncheck()
339 if (t
>= ldapfailflag
)
344 static int read_env(const char *env
, const char **copy
,
345 const char *errstr
, int needit
, const char *value_default
);
346 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
347 char **copy
, const char *username
);
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
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
362 static int read_env(const char *env
, const char **copy
,
363 const char *errstr
, int needit
, const char *value_default
)
365 static char *ldapauth
=0;
366 static size_t ldapauth_size
=0;
373 FILE *f
=fopen(AUTHLDAPRC
, "r");
377 if (fstat(fileno(f
), &buf
) ||
378 (ldapauth
=malloc(buf
.st_size
+2)) == 0)
383 if (fread(ldapauth
, buf
.st_size
, 1, f
) != 1)
390 ldapauth
[ldapauth_size
=buf
.st_size
]=0;
392 for (i
=0; i
<ldapauth_size
; i
++)
393 if (ldapauth
[i
] == '\n')
398 for (i
=0; i
<ldapauth_size
; )
401 if (memcmp(p
, env
, l
) == 0 &&
402 isspace((int)(unsigned char)p
[l
]))
405 while (*p
&& *p
!= '\n' &&
406 isspace((int)(unsigned char)*p
))
411 while (i
< ldapauth_size
)
412 if (ldapauth
[i
++] == 0) break;
415 if (i
< ldapauth_size
)
435 * Function: authldap_read_config
436 * Read Configuration from the environnement table
438 * $ldap: a structure where we place information
442 static int authldap_read_config(struct ldap_info
*ldap
)
444 struct passwd
*pwent
;
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
]);
455 free(ldap
->attrlist
);
457 free(ldap
->auxnames
);
458 if (ldap
->auxoptions
)
459 free(ldap
->auxoptions
);
461 memset(ldap
,0,sizeof(struct ldap_info
));
463 if (!read_env("LDAP_URI",&ldap
->uri
,
464 "You need to specify LDAP_URI in config file",1,NULL
))
467 if (!read_env("LDAP_AUTHBIND", &p
, "", 0, ""))
471 sscanf(p
,"%d",&ldap
->authbind
);
473 if (!read_env("LDAP_INITBIND", &p
, "", 0, "1"))
477 sscanf(p
,"%d",&ldap
->initbind
);
479 if (!read_env("LDAP_BASEDN",&ldap
->basedn
,
480 "You need to specify a basedn in config file",1,NULL
))
482 if (!read_env("LDAP_BINDDN",&ldap
->binddn
,
483 "You need to specify a BINDDN in config file",0,NULL
))
485 if (!read_env("LDAP_BINDPW",&ldap
->bindpw
,
486 "You need to specify a password for the BINDDN in config file",0,NULL
))
488 if (!read_env("LDAP_MAIL",&ldap
->mail
,
489 "You need to specify a attribute for mail in config file",0,"mail"))
491 if (!read_env("LDAP_DOMAIN",&ldap
->domain
,
492 "You need to specify a domain for mail in config file",0,""))
497 if (!read_env("LDAP_GLOB_UID", &p
, "", 0, ""))
504 if (sscanf(p
, "%lu", &n
) == 1)
511 err("authldap: INVALID LDAP_GLOB_UID");
514 ldap
->uid
=pwent
->pw_uid
;
520 if (!read_env("LDAP_GLOB_GID", &p
, "", 0, ""))
527 if (sscanf(p
, "%lu", &n
) == 1)
534 err("authldap: INVALID LDAP_GLOB_GID");
537 ldap
->gid
=grent
->gr_gid
;
543 if (read_env("LDAP_TIMEOUT", &p
, "", 0, "") && p
)
545 sscanf(p
,"%d",&ldap
->timeout
);
550 if (read_env("LDAP_TLS", &p
, "", 0, "") && p
)
557 if (read_env("LDAP_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
562 ldap
->enumerate_filter
=0;
564 if (read_env("LDAP_ENUMERATE_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
566 ldap
->enumerate_filter
=p
;
568 else if (ldap
->filter
)
570 ldap
->enumerate_filter
=ldap
->filter
;
574 ldap
->enumerate_filter
= malloc(strlen(ldap
->mail
)+3);
575 if (!ldap
->enumerate_filter
)
577 perror("CRIT: authldap: malloc failed");
580 sprintf((char *)ldap
->enumerate_filter
, "%s=*", ldap
->mail
);
583 ldap
->deref
= LDAP_DEREF_NEVER
;
584 ldap
->protocol_version
= 0; /* use API default */
586 if (!read_env("LDAP_DEREF", &p
, "", 0, ""))
590 #ifndef LDAP_OPT_DEREF
591 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
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
;
603 if (!read_env("LDAP_PROTOCOL_VERSION", &p
, 0, 0, 0))
608 #ifndef LDAP_OPT_PROTOCOL_VERSION
609 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
612 #ifdef LDAP_VERSION_MIN
613 || lpv
< LDAP_VERSION_MIN
615 #ifdef LDAP_VERSION_MAX
616 || lpv
> LDAP_VERSION_MAX
619 err("authldaplib: illegal protocol version ignored");
621 ldap
->protocol_version
= lpv
;
624 if (!read_env("LDAP_MAILROOT",&ldap
->mailroot
,"",0,NULL
)
625 || ldap
->mailroot
== NULL
|| ldap
->mailroot
[0] == 0)
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, ""))
636 for (pass
=0; pass
<2; pass
++)
640 if ((ldap
->auxnames
=malloc((i
+1)*sizeof(char *)))
642 (ldap
->auxoptions
=malloc((i
+1)*sizeof(char *)))
645 perror("CRIT: authldap: malloc failed");
655 ldap
->auxnames
[0]=NULL
;
656 ldap
->auxoptions
[0]=NULL
;
659 if (!read_env("LDAP_AUXOPTIONS", &p
, "", 0, NULL
)
660 || p
== NULL
|| *p
== 0)
673 for (n
=0; p
[n
] && p
[n
] != ',' && p
[n
] != '='; n
++)
678 if ((ldap
->auxoptions
[i
]=malloc(n
+1)) == NULL
)
680 perror("CRIT: authldap: malloc failed");
684 memcpy(ldap
->auxoptions
[i
], p
, n
);
685 ldap
->auxoptions
[i
][n
]=0;
686 ldap
->auxoptions
[i
+1]=NULL
;
693 for (n
=0; p
[n
] && p
[n
] != ','; n
++)
700 if ((ldap
->auxnames
[i
]=
701 strdup(ldap
->auxoptions
[i
]))
704 perror("CRIT: authldap: malloc failed");
708 else if ((ldap
->auxnames
[i
]=malloc(n
+1)) == NULL
)
710 perror("CRIT: authldap: malloc failed");
715 memcpy(ldap
->auxnames
[i
], p
, n
);
716 ldap
->auxnames
[i
][n
]=0;
717 ldap
->auxnames
[i
+1]=NULL
;
725 if ((ldap
->attrlist
=malloc((i
+20)*sizeof(const char *))) == NULL
)
727 perror("CRIT: authldap: malloc failed");
734 static void get_error(LDAP
*ld
, LDAPMessage
*entry
,
736 const char *attribut
)
738 #if HAVE_LDAP_PARSE_RESULT
745 if (ldap_parse_result(ld
, entry
, &errcode
, &nmatched
,
746 &errmsg
, NULL
, NULL
, 0)
749 DPRINTF("ldap_parseresult failed");
753 if (errcode
&& errcode
!= LDAP_DECODING_ERROR
&&
754 errcode
!= LDAP_NO_RESULTS_RETURNED
)
756 DPRINTF("get_values attribute %s: %s",
758 errmsg
? errmsg
:"unknown error");
762 ldap_memfree(errmsg
);
764 ldap_memfree(nmatched
);
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
)
772 DPRINTF("get_values attribute %s: %s", attribut
,
773 ldap_err2string(ld_errno
));
776 if (ld
->ld_errno
!= LDAP_DECODING_ERROR
777 && ld
->ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
779 DPRINTF("get_values attribute %s: %s", attribut
,
780 ldap_err2string(ld
->ld_errno
));
786 static char **get_values(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
)
789 values
=l_get_values(ld
,entry
, (char *)attribut
);
793 get_error(ld
, entry
, "get_values", attribut
);
802 * Function: copy_value
803 * Copy value from a LDAP attribute to $copy
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
812 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
813 char **copy
, const char *username
)
816 values
=l_get_values(ld
,entry
, attribut
);
820 get_error(ld
, entry
, "copy_value ", attribut
);
824 /* We accept only attribute with one value */
825 else if (l_count_values(values
)>1)
827 *copy
=strdup(values
[0]);
828 fprintf(stderr
, "WARN: authldaplib: duplicate attribute %s for %s\n",
833 /* We accept only attribute with one value */
834 else if (l_count_values(values
)!=1)
840 *copy
=strdup(values
[0]);
843 DPRINTF("copy_value %s: %s",attribut
,values
[0]);
845 l_value_free(values
);
848 static struct ldap_info my_ldap
;
849 static LDAP
*my_ldap_fp
=0;
850 static LDAP
*bindp
=0; /* for checking passwords with AUTHBIND */
856 l_unbind(my_ldap_fp
);
866 static int ldaperror(int rc
)
869 if (rc
&& !LDAP_NAME_ERROR(rc
))
871 if (rc
&& !NAME_ERROR(rc
))
874 /* If there was a protocol error, close the connection */
881 /* This function takes a ldap connection and
882 * tries to enable TLS on it.
884 static int enable_tls_on(LDAP
*conn
) {
889 if (ldaperror(ldrc
=ldap_get_option (conn
,
890 LDAP_OPT_PROTOCOL_VERSION
,
894 const char *s
=ldap_err2string(ldrc
);
896 err("ldap_get_option failed: %s", s
);
900 if (version
< LDAP_VERSION3
)
902 version
= LDAP_VERSION3
;
903 (void)ldap_set_option (conn
,
904 LDAP_OPT_PROTOCOL_VERSION
,
908 if (ldaperror(ldrc
=ldap_start_tls_s(conn
, NULL
, NULL
))
911 const char *s
=ldap_err2string(ldrc
);
913 err("ldap_start_tls_s failed: %s", s
);
918 err("authldaplib: TLS not available");
923 static LDAP
*ldapconnect()
928 DPRINTF("URI: %s",my_ldap
.uri
);
929 DPRINTF("UID: %d",my_ldap
.uid
);
930 DPRINTF("GID: %d",my_ldap
.gid
);
935 DPRINTF("authldaplib: timing out after failed connection");
939 ldap_initialize(&p
, my_ldap
.uri
);
943 err("cannot connect to LDAP server (%s): %s",
944 my_ldap
.uri
, strerror(errno
));
947 #ifdef LDAP_OPT_NETWORK_TIMEOUT
948 if (my_ldap
.timeout
> 0)
949 ldap_set_option (p
, LDAP_OPT_NETWORK_TIMEOUT
, &my_ldap
.timeout
);
952 DPRINTF("ldapconnect end");
957 static int ldapopen()
961 if (my_ldap_fp
) return (0);
963 if (authldap_read_config(&my_ldap
) == 0)
965 err("authldaplib: error in LDAP configuration file, aborting");
969 my_ldap_fp
=ldapconnect();
976 #ifdef LDAP_OPT_PROTOCOL_VERSION
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
)
983 const char *s
=ldap_err2string(ldrc
);
985 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
986 my_ldap
.protocol_version
, s
);
991 if (my_ldap
.protocol_version
)
993 DPRINTF("selected ldap protocol version %d", my_ldap
.protocol_version
);
997 if (my_ldap
.tls
&& enable_tls_on(my_ldap_fp
))
1004 #ifdef LDAP_OPT_DEREF
1006 /* Set dereferencing mode */
1007 if (ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_DEREF
,
1008 (void *) & my_ldap
.deref
)) != LDAP_SUCCESS
)
1010 const char *s
=ldap_err2string(ldrc
);
1012 err("ldap_set_option(DEREF) failed: %s", s
);
1019 if(my_ldap
.initbind
)
1021 /* Bind to server */
1022 if (courier_authdebug_login_level
>= 2)
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>");
1030 DPRINTF("binding to LDAP server as DN '%s'",
1031 my_ldap
.binddn
? my_ldap
.binddn
: "<null>");
1034 if (ldaperror(ldrc
= l_simple_bind_s(my_ldap_fp
,
1039 const char *s
=ldap_err2string(ldrc
);
1041 err("ldap_simple_bind_s failed: %s", s
);
1050 static int auth_ldap_do(const char *, const char *, const char *,
1051 int (*)(struct authinfo
*, void *),
1052 void *arg
, const char *);
1054 int auth_ldap_changepw(const char *dummy
, const char *user
,
1056 const char *newpass
)
1058 return auth_ldap_do("authlib", user
, pass
, NULL
, NULL
, newpass
);
1062 * Function: authldapcommon
1063 * Get information from the LDAP server ($ldap) for this $user
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.
1070 * < 0 - authentication failure
1071 * > 0 - temporary failure
1072 * else return code from the callback function.
1075 int authldapcommon(const char *service
,
1076 const char *user
, const char *pass
,
1077 int (*callback
)(struct authinfo
*, void *),
1080 return (auth_ldap_do(service
, user
, pass
, callback
, arg
, NULL
));
1083 static 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
);
1088 static 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
);
1093 static 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
)
1098 int rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
, newpass
);
1101 rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
,
1107 static 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
)
1115 q
=courier_auth_ldap_escape(user
);
1123 i
=auth_ldap_do2(service
, q
, pass
, callback
, arg
, newpass
);
1129 static 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
);
1135 static char *emailmap_get_search_string(const char *str
, const char *email
);
1137 static 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
)
1144 const char *attributes
[2];
1145 LDAPMessage
*result
, *entry
;
1150 if (ldapopen()) return (-1);
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
,
1156 /* Mapping is not enabled */
1158 srch
=emailmap_get_search_string(my_ldap
.emailmap
, user
);
1162 perror("CRIT: authldaplib: malloc");
1165 DPRINTF("using emailmap search: %s", srch
);
1167 tv
.tv_sec
=my_ldap
.timeout
;
1170 attributes
[0]=my_ldap
.emailmap_handle
;
1172 if (!attributes
[0][0])
1173 attributes
[0]="handle";
1176 if (ldaperror(l_search_st(my_ldap_fp
,
1177 (char *)(my_ldap
.emailmap_basedn
[0] ?
1178 my_ldap
.emailmap_basedn
1181 srch
, (char **)attributes
, 0,
1187 DPRINTF("ldap_search_st failed");
1188 if (my_ldap_fp
) return (-1);
1192 if ((cnt
=ldap_count_entries(my_ldap_fp
, result
)) != 1)
1195 err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1198 ldap_msgfree(result
);
1203 entry
=ldap_first_entry(my_ldap_fp
, result
);
1207 ldap_msgfree(result
);
1209 err("authldap: unexpected NULL from ldap_first_entry");
1213 copy_value(my_ldap_fp
, entry
, attributes
[0], &v
, user
);
1217 DPRINTF("emailmap: empty attribute");
1218 ldap_msgfree(result
);
1222 aname
=my_ldap
.emailmap_handle_lookup
;
1226 DPRINTF("emailmap results: aname=%s, handle=%s", aname
, v
);
1228 cnt
=auth_ldap_do3(service
,
1229 aname
, v
, pass
, callback
, arg
, newpass
, user
);
1231 ldap_msgfree(result
);
1236 static 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
)
1243 char *newpass_crypt
=0;
1244 const char *attributes
[10];
1245 struct timeval timeout
;
1247 LDAPMessage
*result
;
1252 struct authinfo auth
;
1255 char *userPassword
=0;
1256 char *cryptPassword
=0;
1263 int additionalFilter
= 0;
1264 int hasAdditionalFilter
= 0;
1266 hasAdditionalFilter
= my_ldap
.filter
!= 0;
1268 memset(&auth
, 0, sizeof(auth
));
1270 if (hasAdditionalFilter
)
1272 /* To add the additional filter, we need to add on the
1273 * additional size for "(&)" and the other filter. So
1276 additionalFilter
= strlen(my_ldap
.filter
) + 3;
1279 if ((filter
=malloc(additionalFilter
+strlen(attrname
)+strlen(user
)+
1280 (my_ldap
.domain
? strlen(my_ldap
.domain
):0)+
1281 sizeof ("(=@)"))) == 0)
1286 strcpy(filter
, "\0");
1288 if (hasAdditionalFilter
)
1290 strcat(filter
, "(&");
1291 strcat(filter
, my_ldap
.filter
);
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
, ")");
1299 if (hasAdditionalFilter
)
1301 strcat(filter
, ")");
1304 DPRINTF("using search filter: %s", filter
);
1306 timeout
.tv_sec
=my_ldap
.timeout
;
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);
1325 my_ldap
.attrlist
[j
++]=attributes
[i
];
1328 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1329 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1331 my_ldap
.attrlist
[j
]=0;
1333 if (ldaperror(l_search_st(my_ldap_fp
,
1334 (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1335 filter
, (char **)my_ldap
.attrlist
, 0,
1339 DPRINTF("ldap_search_st() failed");
1342 if (my_ldap_fp
) return (-1);
1348 /* If we are more than one result, reject */
1349 if (ldap_count_entries(my_ldap_fp
,result
)!=1)
1351 DPRINTF("number of entries returned: %d (but we need exactly 1)",
1352 ldap_count_entries(my_ldap_fp
,result
));
1353 ldap_msgfree(result
);
1357 dn
= ldap_get_dn(my_ldap_fp
, result
);
1359 DPRINTF("one entry returned, DN: %s", dn
? dn
: "<null>");
1363 DPRINTF("ldap_get_dn failed");
1367 /* Get the pointer on this result */
1368 entry
=ldap_first_entry(my_ldap_fp
,result
);
1371 DPRINTF("ldap_first_entry failed");
1377 DPRINTF("after ldap_first_entry");
1380 /* print all the raw attributes */
1381 if (courier_authdebug_login_level
>= 2)
1384 BerElement
*berptr
= 0;
1386 attr
= ldap_first_attribute(my_ldap_fp
, entry
, &berptr
);
1389 DPRINTF("raw ldap entry returned:");
1396 av
= l_get_values(my_ldap_fp
, entry
, attr
);
1402 DPRINTF("| %s: %s", attr
, *ap
);
1408 attr
= ldap_next_attribute(my_ldap_fp
, entry
, berptr
);
1411 ber_free(berptr
, 0);
1414 /* Copy the directory and the password into struct */
1415 copy_value(my_ldap_fp
,entry
,attributes
[0],&homeDir
, user
);
1417 copy_value(my_ldap_fp
,entry
,attributes
[1],&mailDir
, user
);
1418 copy_value(my_ldap_fp
,entry
,attributes
[2],&cn
, user
);
1420 copy_value(my_ldap_fp
,entry
,attributes
[3],&userPassword
, user
);
1422 copy_value(my_ldap_fp
,entry
,attributes
[4],&cryptPassword
, user
);
1431 copy_value(my_ldap_fp
, entry
, attributes
[5], &p
, user
);
1433 if (sscanf(p
, "%lu", &n
) > 0)
1438 DPRINTF("au= %d",au
);
1447 copy_value(my_ldap_fp
, entry
, attributes
[6], &p
, user
);
1449 if (sscanf(p
, "%lu", &n
) > 0)
1454 DPRINTF("ag= %d",ag
);
1459 copy_value(my_ldap_fp
,entry
,attributes
[8],"a
, user
);
1461 if (homeDir
!= 0 && my_ldap
.mailroot
!= 0 && *my_ldap
.mailroot
)
1463 char *new_mailroot
=malloc(strlen(homeDir
)+
1464 strlen(my_ldap
.mailroot
)+2);
1468 perror("CRIT: authldap: malloc failed");
1473 strcat(strcat(strcpy(new_mailroot
, my_ldap
.mailroot
),
1476 homeDir
=new_mailroot
;
1482 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1486 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
], &val
,
1492 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
1501 perror("CRIT: authldap: malloc failed");
1508 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1512 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
1520 strcat(options
, ",");
1521 strcat(options
, my_ldap
.auxnames
[i
]);
1522 strcat(options
, "=");
1523 strcat(options
, val
);
1529 auth
.sysuserid
= &au
;
1530 auth
.sysgroupid
= ag
;
1531 auth
.homedir
=homeDir
;
1532 auth
.address
=authaddr
;
1534 auth
.maildir
=mailDir
;
1535 auth
.clearpasswd
=userPassword
;
1536 auth
.passwd
=cryptPassword
;
1538 auth
.options
=options
&& *options
? options
:NULL
;
1545 if (au
== 0 || ag
== 0)
1547 err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1552 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth
,
1553 userPassword
, cryptPassword
);
1557 if (my_ldap
.authbind
)
1561 bindp
=ldapconnect();
1565 DPRINTF("ldapconnect failed");
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
)
1575 err("ldap_set_option(PROTOCOL_VERSION %d) failed",
1576 my_ldap
.protocol_version
);
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");
1592 DPRINTF("rebinding with DN '%s' to validate password", dn
);
1593 ldrc
= l_simple_bind_s(bindp
, dn
, pass
);
1597 DPRINTF("authentication bind successful");
1599 case LDAP_INVALID_CREDENTIALS
:
1600 DPRINTF("authentication bind failed, invalid credentials");
1604 DPRINTF("authentication bind failed, some other problem: %s",
1605 ldap_err2string(ldrc
));
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)
1620 if (rc
== 0 && newpass
)
1622 if ((newpass_crypt
=authcryptpasswd(newpass
,
1630 if (auth
.clearpasswd
)
1632 if (strcmp(pass
,auth
.clearpasswd
))
1634 if (courier_authdebug_login_level
>= 2)
1636 DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
1637 pass
, auth
.clearpasswd
);
1641 DPRINTF("supplied password does not match clearpasswd");
1648 const char *p
=auth
.passwd
;
1652 DPRINTF("no password to compare against!");
1655 else if (authcheckpassword(pass
, p
))
1659 if (rc
== 0 && newpass
&& auth
.passwd
)
1661 if ((newpass_crypt
=authcryptpasswd(newpass
,
1669 if (rc
== 0 && newpass
)
1674 LDAPMod mod_clear
, mod_crypt
;
1675 char *mod_clear_vals
[2], *mod_crypt_vals
[2];
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
;
1684 mod_clear_vals
[0]=(char *)newpass
;
1685 mod_clear_vals
[1]=NULL
;
1689 if (attributes
[4] && newpass_crypt
)
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
;
1696 mod_crypt_vals
[0]=newpass_crypt
;
1697 mod_crypt_vals
[1]=NULL
;
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
)
1716 DPRINTF("LDAP modify failed: %s",
1717 ldap_err2string(ld_errno
));
1723 free(newpass_crypt
);
1726 DPRINTF("before callback rc=%d",rc
);
1729 if (rc
== 0 && callback
)
1731 if (!auth
.clearpasswd
)
1732 auth
.clearpasswd
=pass
;
1733 rc
= (*callback
)(&auth
, arg
);
1735 DPRINTF("after callback rc=%d",rc
);
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
);
1746 if (quota
) free(quota
);
1751 ** Create an emailmap search string. I'm going to wrap this into an external
1752 ** variable, so I'll use generic coding here.
1756 const char *varname
;
1758 const char *varvalue
;
1762 static char *var_expand(const char *, const struct varlist
*);
1764 static char *emailmap_get_search_string(const char *str
, const char *email
)
1766 struct varlist vl
[3];
1767 const char *realmptr
=strrchr(email
, '@');/* Guaranteed nonNULL */
1769 static const char userid
[]="user";
1770 static const char realm
[]="realm";
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
);
1782 return (var_expand(str
, vl
));
1785 static char *var_expand(const char *str
, const struct varlist
*vl
)
1796 ** Pass 1 - count expanded string length, allocate buffer,
1797 ** Pass 2 - generate the string.
1800 for (pass
=0; pass
<2; pass
++)
1804 if ((q
=malloc(cnt
)) == NULL
)
1818 for (j
=0; vl
[j
].varname
; j
++)
1820 if (memcmp(vl
[j
].varname
, p
+1,
1821 vl
[j
].varname_len
) == 0
1822 && p
[vl
[j
].varname_len
+1] == '@')
1828 p
+= vl
[j
].varname_len
+2;
1832 memcpy(r
, vl
[j
].varvalue
,
1833 vl
[j
].varvalue_len
);
1834 r
+= vl
[j
].varvalue_len
;
1836 cnt
+= vl
[j
].varvalue_len
;
1853 void auth_ldap_enumerate( void(*cb_func
)(const char *name
,
1856 const char *homedir
,
1857 const char *maildir
,
1858 const char *options
,
1862 const char *attributes
[5];
1869 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
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);
1883 my_ldap
.attrlist
[j
++]=attributes
[i
];
1886 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1887 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1889 my_ldap
.attrlist
[j
]=0;
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)
1897 DPRINTF("ldap_search failed");
1901 while(1) /* process results as they come in */
1903 struct timeval timeout
;
1904 LDAPMessage
*result
;
1908 timeout
.tv_sec
=my_ldap
.timeout
;
1910 ldrc
= ldap_result(my_ldap_fp
, msgid
, 0, &timeout
, &result
);
1914 DPRINTF("error in ldap_result");
1915 ldap_msgfree(result
);
1918 DPRINTF("timeout waiting for search result");
1919 ldap_msgfree(result
);
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
)
1927 DPRINTF("ldap_parse_result failed");
1928 ldap_msgfree(result
);
1931 ldap_msgfree(result
);
1932 if (ldrc
!= LDAP_SUCCESS
)
1934 DPRINTF("ldap search failure result: %s",
1935 ldap_err2string(ldrc
));
1938 /* Search successfully completed */
1939 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1942 DPRINTF("ldap result type 0x%02X ignored", ldrc
);
1943 ldap_msgfree(result
);
1947 entry
= ldap_first_entry(my_ldap_fp
, result
);
1950 char **names
= get_values(my_ldap_fp
, entry
, attributes
[0]);
1955 entry
= ldap_next_entry(my_ldap_fp
, entry
);
1959 n
=l_count_values(names
);
1962 const char *name
= names
[0] ? names
[0] : "<null>";
1969 uid_t uid
=my_ldap
.uid
;
1970 gid_t gid
=my_ldap
.gid
;
1974 copy_value(my_ldap_fp
, entry
, attributes
[1],
1981 copy_value(my_ldap_fp
, entry
, attributes
[2],
1985 copy_value(my_ldap_fp
, entry
, attributes
[3],
1987 copy_value(my_ldap_fp
, entry
, attributes
[4],
1997 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2001 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2007 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
2016 l_value_free(names
);
2017 perror("CRIT: auth_ldap_enumerate: malloc failed");
2022 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2026 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2033 strcat(options
, ",");
2034 strcat(options
, my_ldap
.auxnames
[i
]);
2035 strcat(options
, "=");
2036 strcat(options
, val
);
2040 for (j
= 0; j
< n
; j
++)
2044 if (name
&& homedir
)
2045 (*cb_func
)(name
, uid
, gid
, homedir
,
2046 maildir
, options
, void_arg
);
2060 l_value_free(names
);
2062 entry
= ldap_next_entry(my_ldap_fp
, entry
);
2065 ldap_msgfree(result
);