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., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, 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
);
151 if ((a
[i
]=malloc(p
[i
]->bv_len
+1)) == NULL
)
153 DPRINTF("malloc failed");
159 ldap_value_free_len(p
);
163 memcpy(a
[i
], p
[i
]->bv_val
, p
[i
]->bv_len
);
164 a
[i
][p
[i
]->bv_len
]=0;
167 ldap_value_free_len(p
);
172 static void l_value_free(char **p
)
181 static int l_count_values(char **p
)
190 static int l_unbind(LDAP
*ld
)
192 return ldap_unbind_ext(ld
, NULL
, NULL
);
195 static int l_simple_bind_s(LDAP
*ld
,
201 cred
.bv_len
=passwd
? strlen(passwd
):0;
202 cred
.bv_val
=(char *)passwd
;
204 return ldap_sasl_bind_s(ld
, who
, NULL
, &cred
, NULL
, NULL
, NULL
);
207 static int l_search_st(LDAP
*ld
,
213 struct timeval
*timeout
,
216 return ldap_search_ext_s(ld
, base
, scope
, filter
, attrs
,
224 static int l_modify_s(LDAP
*ld
,
228 return ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
231 static int l_search(LDAP
*ld
,
244 if (ldap_search_ext(ld
, base
, scope
, filter
, attrs
, attrsonly
,
245 NULL
, NULL
, &tv
, 1000000, &msgid
) !=
260 const char *enumerate_filter
;
268 int protocol_version
;
271 const char *mailroot
;
275 const char **attrlist
;
277 /* Optional emailmap to handle */
279 const char *emailmap
;
280 const char *emailmap_basedn
;
281 const char *emailmap_handle
;
282 const char *emailmap_handle_lookup
;
286 ** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
287 ** too. See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
288 ** information. To work around the bug, the first time a connection fails
289 ** we stop trying for 60 seconds. After 60 seconds we kill the process,
290 ** and let the parent process restart it.
292 ** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
293 ** off this behavior (whenever OpenLDAP gets fixed).
296 static time_t ldapfailflag
=0;
298 static void ldapconnfailure()
300 const char *p
=getenv("LDAP_MEMORY_LEAK");
304 #ifdef LDAP_VENDOR_NAME
305 #ifdef LDAP_VENDOR_VERSION
306 #define DO_OPENLDAP_CHECK
310 #ifdef DO_OPENLDAP_CHECK
312 /* It's supposed to be fixed in 20019 */
314 if (strcmp(LDAP_VENDOR_NAME
, "OpenLDAP") == 0 &&
315 LDAP_VENDOR_VERSION
< 20019)
324 if (atoi(p
) && !ldapfailflag
)
331 static int ldapconncheck()
340 if (t
>= ldapfailflag
)
345 static int read_env(const char *env
, const char **copy
,
346 const char *errstr
, int needit
, const char *value_default
);
347 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
348 char **copy
, const char *username
);
352 * Copy the environnement $env and copy to $copy if not null
353 * if needit is false, and env doesn't exist, copy $value_default to $copy
355 * $env: pointer to the environnement name
356 * $copy: where the value go
357 * $err: print a nice message when $env not_found and $needit is true
358 * $needit: if $needit is true and $value not found, return a error
359 * $value_default: the default value when $needit is false and $env doesn't exists
363 static int read_env(const char *env
, const char **copy
,
364 const char *errstr
, int needit
, const char *value_default
)
366 static char *ldapauth
=0;
367 static size_t ldapauth_size
=0;
374 FILE *f
=fopen(AUTHLDAPRC
, "r");
378 if (fstat(fileno(f
), &buf
) ||
379 (ldapauth
=malloc(buf
.st_size
+2)) == 0)
384 if (fread(ldapauth
, buf
.st_size
, 1, f
) != 1)
391 ldapauth
[ldapauth_size
=buf
.st_size
]=0;
393 for (i
=0; i
<ldapauth_size
; i
++)
394 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_BASEDN",&ldap
->basedn
,
474 "You need to specify a basedn in config file",1,NULL
))
476 if (!read_env("LDAP_BINDDN",&ldap
->binddn
,
477 "You need to specify a BINDDN in config file",0,NULL
))
479 if (!read_env("LDAP_BINDPW",&ldap
->bindpw
,
480 "You need to specify a password for the BINDDN in config file",0,NULL
))
482 if (!read_env("LDAP_MAIL",&ldap
->mail
,
483 "You need to specify a attribute for mail in config file",0,"mail"))
485 if (!read_env("LDAP_DOMAIN",&ldap
->domain
,
486 "You need to specify a domain for mail in config file",0,""))
491 if (!read_env("LDAP_GLOB_UID", &p
, "", 0, ""))
498 if (sscanf(p
, "%lu", &n
) == 1)
505 err("authldap: INVALID LDAP_GLOB_UID");
508 ldap
->uid
=pwent
->pw_uid
;
514 if (!read_env("LDAP_GLOB_GID", &p
, "", 0, ""))
521 if (sscanf(p
, "%lu", &n
) == 1)
528 err("authldap: INVALID LDAP_GLOB_GID");
531 ldap
->gid
=grent
->gr_gid
;
537 if (read_env("LDAP_TIMEOUT", &p
, "", 0, "") && p
)
539 sscanf(p
,"%d",&ldap
->timeout
);
544 if (read_env("LDAP_TLS", &p
, "", 0, "") && p
)
551 if (read_env("LDAP_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
556 ldap
->enumerate_filter
=0;
558 if (read_env("LDAP_ENUMERATE_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
560 ldap
->enumerate_filter
=p
;
562 else if (ldap
->filter
)
564 ldap
->enumerate_filter
=ldap
->filter
;
568 ldap
->enumerate_filter
= malloc(strlen(ldap
->mail
)+3);
569 if (!ldap
->enumerate_filter
)
571 perror("CRIT: authldap: malloc failed");
574 sprintf((char *)ldap
->enumerate_filter
, "%s=*", ldap
->mail
);
577 ldap
->deref
= LDAP_DEREF_NEVER
;
578 ldap
->protocol_version
= 0; /* use API default */
580 if (!read_env("LDAP_DEREF", &p
, "", 0, ""))
584 #ifndef LDAP_OPT_DEREF
585 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
587 if (!strcasecmp (p
, "never"))
588 ldap
->deref
= LDAP_DEREF_NEVER
;
589 else if (!strcasecmp (p
, "searching"))
590 ldap
->deref
= LDAP_DEREF_SEARCHING
;
591 else if (!strcasecmp (p
, "finding"))
592 ldap
->deref
= LDAP_DEREF_FINDING
;
593 else if (!strcasecmp (p
, "always"))
594 ldap
->deref
= LDAP_DEREF_ALWAYS
;
597 if (!read_env("LDAP_PROTOCOL_VERSION", &p
, 0, 0, 0))
602 #ifndef LDAP_OPT_PROTOCOL_VERSION
603 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
606 #ifdef LDAP_VERSION_MIN
607 || lpv
< LDAP_VERSION_MIN
609 #ifdef LDAP_VERSION_MAX
610 || lpv
> LDAP_VERSION_MAX
613 err("authldaplib: illegal protocol version ignored");
615 ldap
->protocol_version
= lpv
;
618 if (!read_env("LDAP_MAILROOT",&ldap
->mailroot
,"",0,NULL
)
619 || ldap
->mailroot
== NULL
|| ldap
->mailroot
[0] == 0)
622 if (!read_env("LDAP_EMAILMAP", &ldap
->emailmap
, "", 0, "") ||
623 !read_env("LDAP_EMAILMAP_BASEDN", &ldap
->emailmap_basedn
, "", 0, "") ||
624 !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap
->emailmap_handle
, "", 0, "")||
625 !read_env("LDAP_EMAILMAP_MAIL",
626 &ldap
->emailmap_handle_lookup
, "", 0, ""))
630 for (pass
=0; pass
<2; pass
++)
634 if ((ldap
->auxnames
=malloc((i
+1)*sizeof(char *)))
636 (ldap
->auxoptions
=malloc((i
+1)*sizeof(char *)))
639 perror("CRIT: authldap: malloc failed");
649 ldap
->auxnames
[0]=NULL
;
650 ldap
->auxoptions
[0]=NULL
;
653 if (!read_env("LDAP_AUXOPTIONS", &p
, "", 0, NULL
)
654 || p
== NULL
|| *p
== 0)
667 for (n
=0; p
[n
] && p
[n
] != ',' && p
[n
] != '='; n
++)
672 if ((ldap
->auxoptions
[i
]=malloc(n
+1)) == NULL
)
674 perror("CRIT: authldap: malloc failed");
678 memcpy(ldap
->auxoptions
[i
], p
, n
);
679 ldap
->auxoptions
[i
][n
]=0;
680 ldap
->auxoptions
[i
+1]=NULL
;
687 for (n
=0; p
[n
] && p
[n
] != ','; n
++)
694 if ((ldap
->auxnames
[i
]=
695 strdup(ldap
->auxoptions
[i
]))
698 perror("CRIT: authldap: malloc failed");
702 else if ((ldap
->auxnames
[i
]=malloc(n
+1)) == NULL
)
704 perror("CRIT: authldap: malloc failed");
709 memcpy(ldap
->auxnames
[i
], p
, n
);
710 ldap
->auxnames
[i
][n
]=0;
711 ldap
->auxnames
[i
+1]=NULL
;
719 if ((ldap
->attrlist
=malloc((i
+20)*sizeof(const char *))) == NULL
)
721 perror("CRIT: authldap: malloc failed");
728 static void get_error(LDAP
*ld
, LDAPMessage
*entry
,
730 const char *attribut
)
732 #if HAVE_LDAP_PARSE_RESULT
739 if (ldap_parse_result(ld
, entry
, &errcode
, &nmatched
,
740 &errmsg
, NULL
, NULL
, 0)
743 DPRINTF("ldap_parseresult failed");
747 if (errcode
&& errcode
!= LDAP_DECODING_ERROR
&&
748 errcode
!= LDAP_NO_RESULTS_RETURNED
)
750 DPRINTF("get_values attribute %s: %s",
752 errmsg
? errmsg
:"unknown error");
756 ldap_memfree(errmsg
);
758 ldap_memfree(nmatched
);
761 #if HAVE_LDAP_RESULT2ERROR
762 int ld_errno
= ldap_result2error(ld
,entry
,0);
763 if (ld_errno
&& ld_errno
!= LDAP_DECODING_ERROR
764 && ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
766 DPRINTF("get_values attribute %s: %s", attribut
,
767 ldap_err2string(ld_errno
));
770 if (ld
->ld_errno
!= LDAP_DECODING_ERROR
771 && ld
->ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
773 DPRINTF("get_values attribute %s: %s", attribut
,
774 ldap_err2string(ld
->ld_errno
));
780 static char **get_values(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
)
783 values
=l_get_values(ld
,entry
, (char *)attribut
);
787 get_error(ld
, entry
, "get_values", attribut
);
796 * Function: copy_value
797 * Copy value from a LDAP attribute to $copy
799 * $ld: the connection with the LDAP server
800 * $entry: the entry who contains attributes
801 * $attribut: this attribut
802 * $copy: where data can go
806 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
807 char **copy
, const char *username
)
810 values
=l_get_values(ld
,entry
, attribut
);
814 get_error(ld
, entry
, "copy_value ", attribut
);
818 /* We accept only attribute with one value */
819 else if (l_count_values(values
)>1)
821 *copy
=strdup(values
[0]);
822 fprintf(stderr
, "WARN: authldaplib: duplicate attribute %s for %s\n",
827 /* We accept only attribute with one value */
828 else if (l_count_values(values
)!=1)
834 *copy
=strdup(values
[0]);
837 DPRINTF("copy_value %s: %s",attribut
,values
[0]);
839 l_value_free(values
);
842 static struct ldap_info my_ldap
;
843 static LDAP
*my_ldap_fp
=0;
844 static LDAP
*bindp
=0; /* for checking passwords with AUTHBIND */
850 l_unbind(my_ldap_fp
);
860 static int ldaperror(int rc
)
863 if (rc
&& !LDAP_NAME_ERROR(rc
))
865 if (rc
&& !NAME_ERROR(rc
))
868 /* If there was a protocol error, close the connection */
875 /* This function takes a ldap connection and
876 * tries to enable TLS on it.
878 static int enable_tls_on(LDAP
*conn
) {
883 if (ldaperror(ldrc
=ldap_get_option (conn
,
884 LDAP_OPT_PROTOCOL_VERSION
,
888 const char *s
=ldap_err2string(ldrc
);
890 err("ldap_get_option failed: %s", s
);
894 if (version
< LDAP_VERSION3
)
896 version
= LDAP_VERSION3
;
897 (void)ldap_set_option (conn
,
898 LDAP_OPT_PROTOCOL_VERSION
,
902 if (ldaperror(ldrc
=ldap_start_tls_s(conn
, NULL
, NULL
))
905 const char *s
=ldap_err2string(ldrc
);
907 err("ldap_start_tls_s failed: %s", s
);
912 err("authldaplib: TLS not available");
917 static LDAP
*ldapconnect()
922 DPRINTF("URI: %s",my_ldap
.uri
);
923 DPRINTF("UID: %d",my_ldap
.uid
);
924 DPRINTF("GID: %d",my_ldap
.gid
);
929 DPRINTF("authldaplib: timing out after failed connection");
933 ldap_initialize(&p
, my_ldap
.uri
);
937 err("cannot connect to LDAP server (%s): %s",
938 my_ldap
.uri
, strerror(errno
));
941 #ifdef LDAP_OPT_NETWORK_TIMEOUT
942 if (my_ldap
.timeout
> 0)
943 ldap_set_option (p
, LDAP_OPT_NETWORK_TIMEOUT
, &my_ldap
.timeout
);
946 DPRINTF("ldapconnect end");
951 static int ldapopen()
955 if (my_ldap_fp
) return (0);
957 if (authldap_read_config(&my_ldap
) == 0)
959 err("authldaplib: error in LDAP configuration file, aborting");
963 my_ldap_fp
=ldapconnect();
970 #ifdef LDAP_OPT_PROTOCOL_VERSION
972 /* Set protocol version if selected */
973 if (my_ldap
.protocol_version
&&
974 ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_PROTOCOL_VERSION
,
975 (void *) & my_ldap
.protocol_version
)) != LDAP_SUCCESS
)
977 const char *s
=ldap_err2string(ldrc
);
979 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
980 my_ldap
.protocol_version
, s
);
985 if (my_ldap
.protocol_version
)
987 DPRINTF("selected ldap protocol version %d", my_ldap
.protocol_version
);
991 if (my_ldap
.tls
&& enable_tls_on(my_ldap_fp
))
998 #ifdef LDAP_OPT_DEREF
1000 /* Set dereferencing mode */
1001 if (ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_DEREF
,
1002 (void *) & my_ldap
.deref
)) != LDAP_SUCCESS
)
1004 const char *s
=ldap_err2string(ldrc
);
1006 err("ldap_set_option(DEREF) failed: %s", s
);
1013 /* Bind to server */
1014 if (courier_authdebug_login_level
>= 2)
1016 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
1017 my_ldap
.binddn
? my_ldap
.binddn
: "<null>",
1018 my_ldap
.bindpw
? my_ldap
.bindpw
: "<null>");
1022 DPRINTF("binding to LDAP server as DN '%s'",
1023 my_ldap
.binddn
? my_ldap
.binddn
: "<null>");
1026 if (ldaperror(ldrc
= l_simple_bind_s(my_ldap_fp
,
1028 my_ldap
.bindpw
)) != LDAP_SUCCESS
)
1030 const char *s
=ldap_err2string(ldrc
);
1032 err("ldap_simple_bind_s failed: %s", s
);
1040 static int auth_ldap_do(const char *, const char *, const char *,
1041 int (*)(struct authinfo
*, void *),
1042 void *arg
, const char *);
1044 int auth_ldap_changepw(const char *dummy
, const char *user
,
1046 const char *newpass
)
1048 return auth_ldap_do("authlib", user
, pass
, NULL
, NULL
, newpass
);
1052 * Function: authldapcommon
1053 * Get information from the LDAP server ($ldap) for this $user
1055 * $user: the login name
1056 * $pass: the login password (NULL if we don't want to check the pw)
1057 * callback - callback function with filled in authentication info
1058 * arg - extra argument for the callback function.
1060 * < 0 - authentication failure
1061 * > 0 - temporary failure
1062 * else return code from the callback function.
1065 int authldapcommon(const char *service
,
1066 const char *user
, const char *pass
,
1067 int (*callback
)(struct authinfo
*, void *),
1070 return (auth_ldap_do(service
, user
, pass
, callback
, arg
, NULL
));
1073 static int auth_ldap_do2(const char *service
,
1074 const char *user
, const char *pass
,
1075 int (*callback
)(struct authinfo
*, void *),
1076 void *arg
, const char *newpass
);
1078 static char *escape_str(const char *);
1080 static int auth_ldap_retry(const char *service
,
1081 const char *user
, const char *pass
,
1082 int (*callback
)(struct authinfo
*, void *),
1083 void *arg
, const char *newpass
);
1085 static int auth_ldap_do(const char *service
,
1086 const char *user
, const char *pass
,
1087 int (*callback
)(struct authinfo
*, void *),
1088 void *arg
, const char *newpass
)
1090 int rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
, newpass
);
1093 rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
,
1099 static int auth_ldap_retry(const char *service
,
1100 const char *user
, const char *pass
,
1101 int (*callback
)(struct authinfo
*, void *),
1102 void *arg
, const char *newpass
)
1110 return (auth_ldap_do2(service
,
1111 user
, pass
, callback
, arg
, newpass
));
1113 i
=auth_ldap_do2(service
, q
, pass
, callback
, arg
, newpass
);
1119 static int auth_ldap_do3(const char *service
,
1120 const char *attrname
,
1121 const char *user
, const char *pass
,
1122 int (*callback
)(struct authinfo
*, void *),
1123 void *arg
, const char *newpass
, const char *authaddr
);
1125 static char *emailmap_get_search_string(const char *str
, const char *email
);
1127 static int auth_ldap_do2(const char *service
,
1128 const char *user
, const char *pass
,
1129 int (*callback
)(struct authinfo
*, void *),
1130 void *arg
, const char *newpass
)
1134 const char *attributes
[2];
1135 LDAPMessage
*result
, *entry
;
1140 if (ldapopen()) return (1);
1142 if (my_ldap
.emailmap
[0] == 0 || strchr(user
, '@') == NULL
)
1143 return (auth_ldap_do3(service
, my_ldap
.mail
,
1144 user
, pass
, callback
, arg
, newpass
,
1146 /* Mapping is not enabled */
1148 srch
=emailmap_get_search_string(my_ldap
.emailmap
, user
);
1152 perror("CRIT: authldaplib: malloc");
1155 DPRINTF("using emailmap search: %s", srch
);
1157 tv
.tv_sec
=my_ldap
.timeout
;
1160 attributes
[0]=my_ldap
.emailmap_handle
;
1162 if (!attributes
[0][0])
1163 attributes
[0]="handle";
1166 if (ldaperror(l_search_st(my_ldap_fp
,
1167 (char *)(my_ldap
.emailmap_basedn
[0] ?
1168 my_ldap
.emailmap_basedn
1171 srch
, (char **)attributes
, 0,
1177 DPRINTF("ldap_search_st failed");
1178 if (my_ldap_fp
) return (-1);
1182 if ((cnt
=ldap_count_entries(my_ldap_fp
, result
)) != 1)
1187 err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1189 ldap_msgfree(result
);
1194 entry
=ldap_first_entry(my_ldap_fp
, result
);
1198 ldap_msgfree(result
);
1200 err("authldap: unexpected NULL from ldap_first_entry");
1204 copy_value(my_ldap_fp
, entry
, attributes
[0], &v
, user
);
1208 DPRINTF("emailmap: empty attribute");
1209 ldap_msgfree(result
);
1213 aname
=my_ldap
.emailmap_handle_lookup
;
1217 DPRINTF("emailmap results: aname=%s, handle=%s", aname
, v
);
1219 cnt
=auth_ldap_do3(service
,
1220 aname
, v
, pass
, callback
, arg
, newpass
, user
);
1222 ldap_msgfree(result
);
1227 static int auth_ldap_do3(const char *service
,
1228 const char *attrname
,
1229 const char *user
, const char *pass
,
1230 int (*callback
)(struct authinfo
*, void *),
1231 void *arg
, const char *newpass
,
1232 const char *authaddr
)
1234 char *newpass_crypt
=0;
1235 const char *attributes
[10];
1236 struct timeval timeout
;
1238 LDAPMessage
*result
;
1243 struct authinfo auth
;
1246 char *userPassword
=0;
1247 char *cryptPassword
=0;
1254 int additionalFilter
= 0;
1255 int hasAdditionalFilter
= 0;
1257 hasAdditionalFilter
= my_ldap
.filter
!= 0;
1259 memset(&auth
, 0, sizeof(auth
));
1261 if (hasAdditionalFilter
)
1263 /* To add the additional filter, we need to add on the
1264 * additional size for "(&)" and the other filter. So
1267 additionalFilter
= strlen(my_ldap
.filter
) + 3;
1270 if ((filter
=malloc(additionalFilter
+strlen(attrname
)+strlen(user
)+
1271 (my_ldap
.domain
? strlen(my_ldap
.domain
):0)+
1272 sizeof ("(=@)"))) == 0)
1277 strcpy(filter
, "\0");
1279 if (hasAdditionalFilter
)
1281 strcat(filter
, "(&");
1282 strcat(filter
, my_ldap
.filter
);
1285 strcat(strcat(strcat(strcat(filter
, "("), attrname
), "="), user
);
1286 if ( my_ldap
.domain
&& my_ldap
.domain
[0] && strchr(user
, '@') == 0 )
1287 strcat(strcat(filter
, "@"), my_ldap
.domain
);
1288 strcat(filter
, ")");
1290 if (hasAdditionalFilter
)
1292 strcat(filter
, ")");
1295 DPRINTF("using search filter: %s", filter
);
1297 timeout
.tv_sec
=my_ldap
.timeout
;
1300 read_env("LDAP_HOMEDIR", &attributes
[0], "", 0, "homeDir");
1301 read_env(service
&& strcmp(service
, "courier") == 0
1302 ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR",
1303 &attributes
[1], "", 0, 0);
1304 read_env("LDAP_FULLNAME", &attributes
[2], "", 0, "cn");
1305 read_env("LDAP_CLEARPW", &attributes
[3], "", 0, 0);
1306 read_env("LDAP_CRYPTPW", &attributes
[4], "", 0, 0);
1307 read_env("LDAP_UID", &attributes
[5], "", 0, 0);
1308 read_env("LDAP_GID", &attributes
[6], "", 0, 0);
1309 attributes
[7]=my_ldap
.mail
;
1310 read_env("LDAP_MAILDIRQUOTA", &attributes
[8], "", 0, 0);
1316 my_ldap
.attrlist
[j
++]=attributes
[i
];
1319 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1320 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1322 my_ldap
.attrlist
[j
]=0;
1324 if (ldaperror(l_search_st(my_ldap_fp
,
1325 (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1326 filter
, (char **)my_ldap
.attrlist
, 0,
1330 DPRINTF("ldap_search_st() failed");
1333 if (my_ldap_fp
) return (-1);
1339 /* If we are more than one result, reject */
1340 if (ldap_count_entries(my_ldap_fp
,result
)!=1)
1342 DPRINTF("number of entries returned: %d (but we need exactly 1)",
1343 ldap_count_entries(my_ldap_fp
,result
));
1344 ldap_msgfree(result
);
1348 dn
= ldap_get_dn(my_ldap_fp
, result
);
1350 DPRINTF("one entry returned, DN: %s", dn
? dn
: "<null>");
1354 DPRINTF("ldap_get_dn failed");
1358 /* Get the pointer on this result */
1359 entry
=ldap_first_entry(my_ldap_fp
,result
);
1362 DPRINTF("ldap_first_entry failed");
1368 DPRINTF("after ldap_first_entry");
1371 /* print all the raw attributes */
1372 if (courier_authdebug_login_level
>= 2)
1375 BerElement
*berptr
= 0;
1377 attr
= ldap_first_attribute(my_ldap_fp
, entry
, &berptr
);
1380 DPRINTF("raw ldap entry returned:");
1387 av
= l_get_values(my_ldap_fp
, entry
, attr
);
1393 DPRINTF("| %s: %s", attr
, *ap
);
1399 attr
= ldap_next_attribute(my_ldap_fp
, entry
, berptr
);
1402 ber_free(berptr
, 0);
1405 /* Copy the directory and the password into struct */
1406 copy_value(my_ldap_fp
,entry
,attributes
[0],&homeDir
, user
);
1408 copy_value(my_ldap_fp
,entry
,attributes
[1],&mailDir
, user
);
1409 copy_value(my_ldap_fp
,entry
,attributes
[2],&cn
, user
);
1411 copy_value(my_ldap_fp
,entry
,attributes
[3],&userPassword
, user
);
1413 copy_value(my_ldap_fp
,entry
,attributes
[4],&cryptPassword
, user
);
1422 copy_value(my_ldap_fp
, entry
, attributes
[5], &p
, user
);
1424 if (sscanf(p
, "%lu", &n
) > 0)
1429 DPRINTF("au= %d",au
);
1438 copy_value(my_ldap_fp
, entry
, attributes
[6], &p
, user
);
1440 if (sscanf(p
, "%lu", &n
) > 0)
1445 DPRINTF("ag= %d",ag
);
1450 copy_value(my_ldap_fp
,entry
,attributes
[8],"a
, user
);
1452 if (homeDir
!= 0 && my_ldap
.mailroot
!= 0 && *my_ldap
.mailroot
)
1454 char *new_mailroot
=malloc(strlen(homeDir
)+
1455 strlen(my_ldap
.mailroot
)+2);
1459 perror("CRIT: authldap: malloc failed");
1464 strcat(strcat(strcpy(new_mailroot
, my_ldap
.mailroot
),
1467 homeDir
=new_mailroot
;
1473 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1477 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
], &val
,
1483 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
1492 perror("CRIT: authldap: malloc failed");
1499 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1503 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
1511 strcat(options
, ",");
1512 strcat(options
, my_ldap
.auxnames
[i
]);
1513 strcat(options
, "=");
1514 strcat(options
, val
);
1520 auth
.sysuserid
= &au
;
1521 auth
.sysgroupid
= ag
;
1522 auth
.homedir
=homeDir
;
1523 auth
.address
=authaddr
;
1525 auth
.maildir
=mailDir
;
1526 auth
.clearpasswd
=userPassword
;
1527 auth
.passwd
=cryptPassword
;
1529 auth
.options
=options
&& *options
? options
:NULL
;
1536 if (au
== 0 || ag
== 0)
1538 err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1543 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth
,
1544 userPassword
, cryptPassword
);
1548 if (my_ldap
.authbind
)
1552 bindp
=ldapconnect();
1556 DPRINTF("ldapconnect failed");
1560 #ifdef LDAP_OPT_PROTOCOL_VERSION
1561 /* Set protocol version */
1562 if (my_ldap
.protocol_version
&&
1563 ldap_set_option(bindp
, LDAP_OPT_PROTOCOL_VERSION
,
1564 (void *) & my_ldap
.protocol_version
) != LDAP_OPT_SUCCESS
)
1566 err("ldap_set_option(PROTOCOL_VERSION %d) failed",
1567 my_ldap
.protocol_version
);
1572 if(my_ldap
.tls
&& enable_tls_on(bindp
)) {
1573 err("authldaplib: LDAP_TLS enabled but I'm unable to start tls, check your config");
1583 DPRINTF("rebinding with DN '%s' to validate password", dn
);
1584 ldrc
= l_simple_bind_s(bindp
, dn
, pass
);
1588 DPRINTF("authentication bind successful");
1590 case LDAP_INVALID_CREDENTIALS
:
1591 DPRINTF("authentication bind failed, invalid credentials");
1595 DPRINTF("authentication bind failed, some other problem: %s",
1596 ldap_err2string(ldrc
));
1601 /* Drop the connection if there was a fatal
1602 error or if we are using historic LDAP v2,
1603 which didn't support rebinding on same conn */
1604 if (rc
> 0 || my_ldap
.protocol_version
== 2)
1611 if (rc
== 0 && newpass
)
1613 if ((newpass_crypt
=authcryptpasswd(newpass
,
1621 if (auth
.clearpasswd
)
1623 if (strcmp(pass
,auth
.clearpasswd
))
1625 if (courier_authdebug_login_level
>= 2)
1627 DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
1628 pass
, auth
.clearpasswd
);
1632 DPRINTF("supplied password does not match clearpasswd");
1639 const char *p
=auth
.passwd
;
1643 DPRINTF("no password to compare against!");
1646 else if (authcheckpassword(pass
, p
))
1650 if (rc
== 0 && newpass
&& auth
.passwd
)
1652 if ((newpass_crypt
=authcryptpasswd(newpass
,
1660 if (rc
== 0 && newpass
)
1665 LDAPMod mod_clear
, mod_crypt
;
1666 char *mod_clear_vals
[2], *mod_crypt_vals
[2];
1670 mods
[mod_index
]= &mod_clear
;
1671 mod_clear
.mod_op
=LDAP_MOD_REPLACE
;
1672 mod_clear
.mod_type
=(char *)attributes
[3];
1673 mod_clear
.mod_values
=mod_clear_vals
;
1675 mod_clear_vals
[0]=(char *)newpass
;
1676 mod_clear_vals
[1]=NULL
;
1680 if (attributes
[4] && newpass_crypt
)
1682 mods
[mod_index
]= &mod_crypt
;
1683 mod_crypt
.mod_op
=LDAP_MOD_REPLACE
;
1684 mod_crypt
.mod_type
=(char *)attributes
[4];
1685 mod_crypt
.mod_values
=mod_crypt_vals
;
1687 mod_crypt_vals
[0]=newpass_crypt
;
1688 mod_crypt_vals
[1]=NULL
;
1698 /* On a system which uses LDAP_AUTHBIND, we probably
1699 want to use the user's credentials (bindp) rather
1700 than the search credentials (my_ldap_fp) for
1701 performing the password update. (May not always be
1702 true, ideally it would be configurable) */
1703 ld_errno
= l_modify_s(bindp
? bindp
:my_ldap_fp
, dn
, mods
);
1704 if (ld_errno
!= LDAP_SUCCESS
)
1707 DPRINTF("LDAP modify failed: %s",
1708 ldap_err2string(ld_errno
));
1714 free(newpass_crypt
);
1717 DPRINTF("before callback rc=%d",rc
);
1720 if (rc
== 0 && callback
)
1722 if (!auth
.clearpasswd
)
1723 auth
.clearpasswd
=pass
;
1724 rc
= (*callback
)(&auth
, arg
);
1726 DPRINTF("after callback rc=%d",rc
);
1730 ldap_msgfree(result
);
1731 if (options
) free(options
);
1732 if (homeDir
) free(homeDir
);
1733 if (mailDir
) free(mailDir
);
1734 if (userPassword
) free(userPassword
);
1735 if (cryptPassword
) free(cryptPassword
);
1737 if (quota
) free(quota
);
1742 ** Escape a string with special LDAP characters. Returns NULL if the original
1743 ** string does not have any special LDAP characters (so we don't allocate
1744 ** memory unless absolutely necessary).
1747 static char *escape_str(const char *user
)
1753 for (i
=0, p
=user
; *p
; p
++)
1754 if (strchr("*()\\", *p
))
1758 return NULL
; /* No need to escape anything */
1760 q
=malloc(strlen(user
)+i
+1);
1768 for (r
=q
, p
=user
; *p
; p
++)
1770 if (strchr("*()\\", *p
))
1779 ** Create an emailmap search string. I'm going to wrap this into an external
1780 ** variable, so I'll use generic coding here.
1784 const char *varname
;
1786 const char *varvalue
;
1790 static char *var_expand(const char *, const struct varlist
*);
1792 static char *emailmap_get_search_string(const char *str
, const char *email
)
1794 struct varlist vl
[3];
1795 const char *realmptr
=strrchr(email
, '@');/* Guaranteed nonNULL */
1797 static const char userid
[]="user";
1798 static const char realm
[]="realm";
1800 vl
[0].varname
=userid
;
1801 vl
[0].varname_len
=sizeof(userid
)-1;
1802 vl
[0].varvalue
=email
;
1803 vl
[0].varvalue_len
=realmptr
- email
;
1804 vl
[1].varname
=realm
;
1805 vl
[1].varname_len
=sizeof(realm
)-1;
1806 vl
[1].varvalue
=realmptr
+1;
1807 vl
[1].varvalue_len
=strlen(vl
[1].varvalue
);
1810 return (var_expand(str
, vl
));
1813 static char *var_expand(const char *str
, const struct varlist
*vl
)
1824 ** Pass 1 - count expanded string length, allocate buffer,
1825 ** Pass 2 - generate the string.
1828 for (pass
=0; pass
<2; pass
++)
1832 if ((q
=malloc(cnt
)) == NULL
)
1846 for (j
=0; vl
[j
].varname
; j
++)
1848 if (memcmp(vl
[j
].varname
, p
+1,
1849 vl
[j
].varname_len
) == 0
1850 && p
[vl
[j
].varname_len
+1] == '@')
1856 p
+= vl
[j
].varname_len
+2;
1860 memcpy(r
, vl
[j
].varvalue
,
1861 vl
[j
].varvalue_len
);
1862 r
+= vl
[j
].varvalue_len
;
1864 cnt
+= vl
[j
].varvalue_len
;
1881 void auth_ldap_enumerate( void(*cb_func
)(const char *name
,
1884 const char *homedir
,
1885 const char *maildir
,
1886 const char *options
,
1890 const char *attributes
[5];
1895 if (ldapopen()) return;
1897 read_env("LDAP_MAIL", &attributes
[0], "", 0, "mail");
1898 read_env("LDAP_UID", &attributes
[1], "", 0, 0);
1899 read_env("LDAP_GID", &attributes
[2], "", 0, 0);
1900 read_env("LDAP_HOMEDIR", &attributes
[3], "", 0, "homeDir");
1901 read_env("LDAP_MAILDIR", &attributes
[4], "", 0, 0);
1907 my_ldap
.attrlist
[j
++]=attributes
[i
];
1910 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1911 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1913 my_ldap
.attrlist
[j
]=0;
1915 DPRINTF("ldap_search: basedn='%s', filter='%s'",
1916 my_ldap
.basedn
, my_ldap
.enumerate_filter
);
1917 if ((msgid
= l_search(my_ldap_fp
, (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1918 my_ldap
.enumerate_filter
,
1919 (char **)my_ldap
.attrlist
, 0)) < 0)
1921 DPRINTF("ldap_search failed");
1925 while(1) /* process results as they come in */
1927 struct timeval timeout
;
1928 LDAPMessage
*result
;
1932 timeout
.tv_sec
=my_ldap
.timeout
;
1934 ldrc
= ldap_result(my_ldap_fp
, msgid
, 0, &timeout
, &result
);
1938 DPRINTF("error in ldap_result");
1939 ldap_msgfree(result
);
1942 DPRINTF("timeout waiting for search result");
1943 ldap_msgfree(result
);
1945 case LDAP_RES_SEARCH_ENTRY
:
1946 break; /* deal with below */
1947 case LDAP_RES_SEARCH_RESULT
:
1948 if (ldap_parse_result(my_ldap_fp
, result
, &ldrc
,
1949 NULL
, NULL
, NULL
, NULL
, 0) != LDAP_SUCCESS
)
1951 DPRINTF("ldap_parse_result failed");
1952 ldap_msgfree(result
);
1955 ldap_msgfree(result
);
1956 if (ldrc
!= LDAP_SUCCESS
)
1958 DPRINTF("ldap search failure result: %s",
1959 ldap_err2string(ldrc
));
1962 /* Search successfully completed */
1963 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1966 DPRINTF("ldap result type 0x%02X ignored", ldrc
);
1967 ldap_msgfree(result
);
1971 entry
= ldap_first_entry(my_ldap_fp
, result
);
1974 char **names
= get_values(my_ldap_fp
, entry
, attributes
[0]);
1979 entry
= ldap_next_entry(my_ldap_fp
, entry
);
1983 n
=l_count_values(names
);
1986 const char *name
= names
[0] ? names
[0] : "<null>";
1993 uid_t uid
=my_ldap
.uid
;
1994 gid_t gid
=my_ldap
.gid
;
1998 copy_value(my_ldap_fp
, entry
, attributes
[1],
2005 copy_value(my_ldap_fp
, entry
, attributes
[2],
2009 copy_value(my_ldap_fp
, entry
, attributes
[3],
2011 copy_value(my_ldap_fp
, entry
, attributes
[4],
2021 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2025 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2031 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
2040 perror("CRIT: auth_ldap_enumerate: malloc failed");
2045 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2049 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2056 strcat(options
, ",");
2057 strcat(options
, my_ldap
.auxnames
[i
]);
2058 strcat(options
, "=");
2059 strcat(options
, val
);
2063 for (j
= 0; j
< n
; j
++)
2067 if (name
&& homedir
)
2068 (*cb_func
)(name
, uid
, gid
, homedir
,
2069 maildir
, options
, void_arg
);
2083 l_value_free(names
);
2085 entry
= ldap_next_entry(my_ldap_fp
, entry
);
2088 ldap_msgfree(result
);