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
);
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
;
266 int protocol_version
;
269 const char *mailroot
;
273 const char **attrlist
;
275 /* Optional emailmap to handle */
277 const char *emailmap
;
278 const char *emailmap_basedn
;
279 const char *emailmap_handle
;
280 const char *emailmap_handle_lookup
;
284 ** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
285 ** too. See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
286 ** information. To work around the bug, the first time a connection fails
287 ** we stop trying for 60 seconds. After 60 seconds we kill the process,
288 ** and let the parent process restart it.
290 ** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
291 ** off this behavior (whenever OpenLDAP gets fixed).
294 static time_t ldapfailflag
=0;
296 static void ldapconnfailure()
298 const char *p
=getenv("LDAP_MEMORY_LEAK");
302 #ifdef LDAP_VENDOR_NAME
303 #ifdef LDAP_VENDOR_VERSION
304 #define DO_OPENLDAP_CHECK
308 #ifdef DO_OPENLDAP_CHECK
310 /* It's supposed to be fixed in 20019 */
312 if (strcmp(LDAP_VENDOR_NAME
, "OpenLDAP") == 0 &&
313 LDAP_VENDOR_VERSION
< 20019)
322 if (atoi(p
) && !ldapfailflag
)
329 static int ldapconncheck()
338 if (t
>= ldapfailflag
)
343 static int read_env(const char *env
, const char **copy
,
344 const char *errstr
, int needit
, const char *value_default
);
345 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
346 char **copy
, const char *username
);
350 * Copy the environnement $env and copy to $copy if not null
351 * if needit is false, and env doesn't exist, copy $value_default to $copy
353 * $env: pointer to the environnement name
354 * $copy: where the value go
355 * $err: print a nice message when $env not_found and $needit is true
356 * $needit: if $needit is true and $value not found, return a error
357 * $value_default: the default value when $needit is false and $env doesn't exists
361 static int read_env(const char *env
, const char **copy
,
362 const char *errstr
, int needit
, const char *value_default
)
364 static char *ldapauth
=0;
365 static size_t ldapauth_size
=0;
372 FILE *f
=fopen(AUTHLDAPRC
, "r");
376 if (fstat(fileno(f
), &buf
) ||
377 (ldapauth
=malloc(buf
.st_size
+2)) == 0)
382 if (fread(ldapauth
, buf
.st_size
, 1, f
) != 1)
389 ldapauth
[ldapauth_size
=buf
.st_size
]=0;
391 for (i
=0; i
<ldapauth_size
; i
++)
392 if (ldapauth
[i
] == '\n')
397 for (i
=0; i
<ldapauth_size
; )
400 if (memcmp(p
, env
, l
) == 0 &&
401 isspace((int)(unsigned char)p
[l
]))
404 while (*p
&& *p
!= '\n' &&
405 isspace((int)(unsigned char)*p
))
410 while (i
< ldapauth_size
)
411 if (ldapauth
[i
++] == 0) break;
414 if (i
< ldapauth_size
)
434 * Function: authldap_read_config
435 * Read Configuration from the environnement table
437 * $ldap: a structure where we place information
441 static int authldap_read_config(struct ldap_info
*ldap
)
443 struct passwd
*pwent
;
448 for (i
=0; ldap
->auxoptions
&& ldap
->auxoptions
[i
]; i
++)
449 free(ldap
->auxoptions
[i
]);
450 for (i
=0; ldap
->auxnames
&& ldap
->auxnames
[i
]; i
++)
451 free(ldap
->auxnames
[i
]);
454 free(ldap
->attrlist
);
456 free(ldap
->auxnames
);
457 if (ldap
->auxoptions
)
458 free(ldap
->auxoptions
);
460 memset(ldap
,0,sizeof(struct ldap_info
));
462 if (!read_env("LDAP_URI",&ldap
->uri
,
463 "You need to specify LDAP_URI in config file",1,NULL
))
466 if (!read_env("LDAP_AUTHBIND", &p
, "", 0, ""))
470 sscanf(p
,"%d",&ldap
->authbind
);
472 if (!read_env("LDAP_BASEDN",&ldap
->basedn
,
473 "You need to specify a basedn in config file",1,NULL
))
475 if (!read_env("LDAP_BINDDN",&ldap
->binddn
,
476 "You need to specify a BINDDN in config file",0,NULL
))
478 if (!read_env("LDAP_BINDPW",&ldap
->bindpw
,
479 "You need to specify a password for the BINDDN in config file",0,NULL
))
481 if (!read_env("LDAP_MAIL",&ldap
->mail
,
482 "You need to specify a attribute for mail in config file",0,"mail"))
484 if (!read_env("LDAP_DOMAIN",&ldap
->domain
,
485 "You need to specify a domain for mail in config file",0,""))
490 if (!read_env("LDAP_GLOB_UID", &p
, "", 0, ""))
497 if (sscanf(p
, "%lu", &n
) == 1)
504 err("authldap: INVALID LDAP_GLOB_UID");
507 ldap
->uid
=pwent
->pw_uid
;
513 if (!read_env("LDAP_GLOB_GID", &p
, "", 0, ""))
520 if (sscanf(p
, "%lu", &n
) == 1)
527 err("authldap: INVALID LDAP_GLOB_GID");
530 ldap
->gid
=grent
->gr_gid
;
536 if (read_env("LDAP_TIMEOUT", &p
, "", 0, "") && p
)
538 sscanf(p
,"%d",&ldap
->timeout
);
543 if (read_env("LDAP_TLS", &p
, "", 0, "") && p
)
550 if (read_env("LDAP_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
555 ldap
->enumerate_filter
=0;
557 if (read_env("LDAP_ENUMERATE_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
559 ldap
->enumerate_filter
=p
;
561 else if (ldap
->filter
)
563 ldap
->enumerate_filter
=ldap
->filter
;
567 ldap
->enumerate_filter
= malloc(strlen(ldap
->mail
)+3);
568 if (!ldap
->enumerate_filter
)
570 perror("CRIT: authldap: malloc failed");
573 sprintf((char *)ldap
->enumerate_filter
, "%s=*", ldap
->mail
);
576 ldap
->deref
= LDAP_DEREF_NEVER
;
577 ldap
->protocol_version
= 0; /* use API default */
579 if (!read_env("LDAP_DEREF", &p
, "", 0, ""))
583 #ifndef LDAP_OPT_DEREF
584 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
586 if (!strcasecmp (p
, "never"))
587 ldap
->deref
= LDAP_DEREF_NEVER
;
588 else if (!strcasecmp (p
, "searching"))
589 ldap
->deref
= LDAP_DEREF_SEARCHING
;
590 else if (!strcasecmp (p
, "finding"))
591 ldap
->deref
= LDAP_DEREF_FINDING
;
592 else if (!strcasecmp (p
, "always"))
593 ldap
->deref
= LDAP_DEREF_ALWAYS
;
596 if (!read_env("LDAP_PROTOCOL_VERSION", &p
, 0, 0, 0))
601 #ifndef LDAP_OPT_PROTOCOL_VERSION
602 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
605 #ifdef LDAP_VERSION_MIN
606 || lpv
< LDAP_VERSION_MIN
608 #ifdef LDAP_VERSION_MAX
609 || lpv
> LDAP_VERSION_MAX
612 err("authldaplib: illegal protocol version ignored");
614 ldap
->protocol_version
= lpv
;
617 if (!read_env("LDAP_MAILROOT",&ldap
->mailroot
,"",0,NULL
)
618 || ldap
->mailroot
== NULL
|| ldap
->mailroot
[0] == 0)
621 if (!read_env("LDAP_EMAILMAP", &ldap
->emailmap
, "", 0, "") ||
622 !read_env("LDAP_EMAILMAP_BASEDN", &ldap
->emailmap_basedn
, "", 0, "") ||
623 !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap
->emailmap_handle
, "", 0, "")||
624 !read_env("LDAP_EMAILMAP_MAIL",
625 &ldap
->emailmap_handle_lookup
, "", 0, ""))
629 for (pass
=0; pass
<2; pass
++)
633 if ((ldap
->auxnames
=malloc((i
+1)*sizeof(char *)))
635 (ldap
->auxoptions
=malloc((i
+1)*sizeof(char *)))
638 perror("CRIT: authldap: malloc failed");
648 ldap
->auxnames
[0]=NULL
;
649 ldap
->auxoptions
[0]=NULL
;
652 if (!read_env("LDAP_AUXOPTIONS", &p
, "", 0, NULL
)
653 || p
== NULL
|| *p
== 0)
666 for (n
=0; p
[n
] && p
[n
] != ',' && p
[n
] != '='; n
++)
671 if ((ldap
->auxoptions
[i
]=malloc(n
+1)) == NULL
)
673 perror("CRIT: authldap: malloc failed");
677 memcpy(ldap
->auxoptions
[i
], p
, n
);
678 ldap
->auxoptions
[i
][n
]=0;
679 ldap
->auxoptions
[i
+1]=NULL
;
686 for (n
=0; p
[n
] && p
[n
] != ','; n
++)
693 if ((ldap
->auxnames
[i
]=
694 strdup(ldap
->auxoptions
[i
]))
697 perror("CRIT: authldap: malloc failed");
701 else if ((ldap
->auxnames
[i
]=malloc(n
+1)) == NULL
)
703 perror("CRIT: authldap: malloc failed");
708 memcpy(ldap
->auxnames
[i
], p
, n
);
709 ldap
->auxnames
[i
][n
]=0;
710 ldap
->auxnames
[i
+1]=NULL
;
718 if ((ldap
->attrlist
=malloc((i
+20)*sizeof(const char *))) == NULL
)
720 perror("CRIT: authldap: malloc failed");
727 static void get_error(LDAP
*ld
, LDAPMessage
*entry
,
729 const char *attribut
)
731 #if HAVE_LDAP_PARSE_RESULT
738 if (ldap_parse_result(ld
, entry
, &errcode
, &nmatched
,
739 &errmsg
, NULL
, NULL
, 0)
742 DPRINTF("ldap_parseresult failed");
746 if (errcode
&& errcode
!= LDAP_DECODING_ERROR
&&
747 errcode
!= LDAP_NO_RESULTS_RETURNED
)
749 DPRINTF("get_values attribute %s: %s",
751 errmsg
? errmsg
:"unknown error");
755 ldap_memfree(errmsg
);
757 ldap_memfree(nmatched
);
760 #if HAVE_LDAP_RESULT2ERROR
761 int ld_errno
= ldap_result2error(ld
,entry
,0);
762 if (ld_errno
&& ld_errno
!= LDAP_DECODING_ERROR
763 && ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
765 DPRINTF("get_values attribute %s: %s", attribut
,
766 ldap_err2string(ld_errno
));
769 if (ld
->ld_errno
!= LDAP_DECODING_ERROR
770 && ld
->ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
772 DPRINTF("get_values attribute %s: %s", attribut
,
773 ldap_err2string(ld
->ld_errno
));
779 static char **get_values(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
)
782 values
=l_get_values(ld
,entry
, (char *)attribut
);
786 get_error(ld
, entry
, "get_values", attribut
);
795 * Function: copy_value
796 * Copy value from a LDAP attribute to $copy
798 * $ld: the connection with the LDAP server
799 * $entry: the entry who contains attributes
800 * $attribut: this attribut
801 * $copy: where data can go
805 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
806 char **copy
, const char *username
)
809 values
=l_get_values(ld
,entry
, attribut
);
813 get_error(ld
, entry
, "copy_value ", attribut
);
817 /* We accept only attribute with one value */
818 else if (l_count_values(values
)>1)
820 *copy
=strdup(values
[0]);
821 fprintf(stderr
, "WARN: authldaplib: duplicate attribute %s for %s\n",
826 /* We accept only attribute with one value */
827 else if (l_count_values(values
)!=1)
833 *copy
=strdup(values
[0]);
836 DPRINTF("copy_value %s: %s",attribut
,values
[0]);
838 l_value_free(values
);
841 static struct ldap_info my_ldap
;
842 static LDAP
*my_ldap_fp
=0;
843 static LDAP
*bindp
=0; /* for checking passwords with AUTHBIND */
849 l_unbind(my_ldap_fp
);
859 static int ldaperror(int rc
)
862 if (rc
&& !LDAP_NAME_ERROR(rc
))
864 if (rc
&& !NAME_ERROR(rc
))
867 /* If there was a protocol error, close the connection */
874 /* This function takes a ldap connection and
875 * tries to enable TLS on it.
877 static int enable_tls_on(LDAP
*conn
) {
882 if (ldaperror(ldrc
=ldap_get_option (conn
,
883 LDAP_OPT_PROTOCOL_VERSION
,
887 const char *s
=ldap_err2string(ldrc
);
889 err("ldap_get_option failed: %s", s
);
893 if (version
< LDAP_VERSION3
)
895 version
= LDAP_VERSION3
;
896 (void)ldap_set_option (conn
,
897 LDAP_OPT_PROTOCOL_VERSION
,
901 if (ldaperror(ldrc
=ldap_start_tls_s(conn
, NULL
, NULL
))
904 const char *s
=ldap_err2string(ldrc
);
906 err("ldap_start_tls_s failed: %s", s
);
911 err("authldaplib: TLS not available");
916 static LDAP
*ldapconnect()
921 DPRINTF("URI: %s",my_ldap
.uri
);
922 DPRINTF("UID: %d",my_ldap
.uid
);
923 DPRINTF("GID: %d",my_ldap
.gid
);
928 DPRINTF("authldaplib: timing out after failed connection");
932 ldap_initialize(&p
, my_ldap
.uri
);
936 err("cannot connect to LDAP server (%s): %s",
937 my_ldap
.uri
, strerror(errno
));
940 #ifdef LDAP_OPT_NETWORK_TIMEOUT
941 if (my_ldap
.timeout
> 0)
942 ldap_set_option (p
, LDAP_OPT_NETWORK_TIMEOUT
, &my_ldap
.timeout
);
945 DPRINTF("ldapconnect end");
950 static int ldapopen()
954 if (my_ldap_fp
) return (0);
956 if (authldap_read_config(&my_ldap
) == 0)
958 err("authldaplib: error in LDAP configuration file, aborting");
962 my_ldap_fp
=ldapconnect();
969 #ifdef LDAP_OPT_PROTOCOL_VERSION
971 /* Set protocol version if selected */
972 if (my_ldap
.protocol_version
&&
973 ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_PROTOCOL_VERSION
,
974 (void *) & my_ldap
.protocol_version
)) != LDAP_SUCCESS
)
976 const char *s
=ldap_err2string(ldrc
);
978 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
979 my_ldap
.protocol_version
, s
);
984 if (my_ldap
.protocol_version
)
986 DPRINTF("selected ldap protocol version %d", my_ldap
.protocol_version
);
990 if (my_ldap
.tls
&& enable_tls_on(my_ldap_fp
))
997 #ifdef LDAP_OPT_DEREF
999 /* Set dereferencing mode */
1000 if (ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_DEREF
,
1001 (void *) & my_ldap
.deref
)) != LDAP_SUCCESS
)
1003 const char *s
=ldap_err2string(ldrc
);
1005 err("ldap_set_option(DEREF) failed: %s", s
);
1012 /* Bind to server */
1013 if (courier_authdebug_login_level
>= 2)
1015 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
1016 my_ldap
.binddn
? my_ldap
.binddn
: "<null>",
1017 my_ldap
.bindpw
? my_ldap
.bindpw
: "<null>");
1021 DPRINTF("binding to LDAP server as DN '%s'",
1022 my_ldap
.binddn
? my_ldap
.binddn
: "<null>");
1025 if (ldaperror(ldrc
= l_simple_bind_s(my_ldap_fp
,
1027 my_ldap
.bindpw
)) != LDAP_SUCCESS
)
1029 const char *s
=ldap_err2string(ldrc
);
1031 err("ldap_simple_bind_s failed: %s", s
);
1039 static int auth_ldap_do(const char *, const char *, const char *,
1040 int (*)(struct authinfo
*, void *),
1041 void *arg
, const char *);
1043 int auth_ldap_changepw(const char *dummy
, const char *user
,
1045 const char *newpass
)
1047 return auth_ldap_do("authlib", user
, pass
, NULL
, NULL
, newpass
);
1051 * Function: authldapcommon
1052 * Get information from the LDAP server ($ldap) for this $user
1054 * $user: the login name
1055 * $pass: the login password (NULL if we don't want to check the pw)
1056 * callback - callback function with filled in authentication info
1057 * arg - extra argument for the callback function.
1059 * < 0 - authentication failure
1060 * > 0 - temporary failure
1061 * else return code from the callback function.
1064 int authldapcommon(const char *service
,
1065 const char *user
, const char *pass
,
1066 int (*callback
)(struct authinfo
*, void *),
1069 return (auth_ldap_do(service
, user
, pass
, callback
, arg
, NULL
));
1072 static int auth_ldap_do2(const char *service
,
1073 const char *user
, const char *pass
,
1074 int (*callback
)(struct authinfo
*, void *),
1075 void *arg
, const char *newpass
);
1077 static int auth_ldap_retry(const char *service
,
1078 const char *user
, const char *pass
,
1079 int (*callback
)(struct authinfo
*, void *),
1080 void *arg
, const char *newpass
);
1082 static int auth_ldap_do(const char *service
,
1083 const char *user
, const char *pass
,
1084 int (*callback
)(struct authinfo
*, void *),
1085 void *arg
, const char *newpass
)
1087 int rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
, newpass
);
1090 rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
,
1096 static int auth_ldap_retry(const char *service
,
1097 const char *user
, const char *pass
,
1098 int (*callback
)(struct authinfo
*, void *),
1099 void *arg
, const char *newpass
)
1104 q
=courier_auth_ldap_escape(user
);
1112 i
=auth_ldap_do2(service
, q
, pass
, callback
, arg
, newpass
);
1118 static int auth_ldap_do3(const char *service
,
1119 const char *attrname
,
1120 const char *user
, const char *pass
,
1121 int (*callback
)(struct authinfo
*, void *),
1122 void *arg
, const char *newpass
, const char *authaddr
);
1124 static char *emailmap_get_search_string(const char *str
, const char *email
);
1126 static int auth_ldap_do2(const char *service
,
1127 const char *user
, const char *pass
,
1128 int (*callback
)(struct authinfo
*, void *),
1129 void *arg
, const char *newpass
)
1133 const char *attributes
[2];
1134 LDAPMessage
*result
, *entry
;
1139 if (ldapopen()) return (1);
1141 if (my_ldap
.emailmap
[0] == 0 || strchr(user
, '@') == NULL
)
1142 return (auth_ldap_do3(service
, my_ldap
.mail
,
1143 user
, pass
, callback
, arg
, newpass
,
1145 /* Mapping is not enabled */
1147 srch
=emailmap_get_search_string(my_ldap
.emailmap
, user
);
1151 perror("CRIT: authldaplib: malloc");
1154 DPRINTF("using emailmap search: %s", srch
);
1156 tv
.tv_sec
=my_ldap
.timeout
;
1159 attributes
[0]=my_ldap
.emailmap_handle
;
1161 if (!attributes
[0][0])
1162 attributes
[0]="handle";
1165 if (ldaperror(l_search_st(my_ldap_fp
,
1166 (char *)(my_ldap
.emailmap_basedn
[0] ?
1167 my_ldap
.emailmap_basedn
1170 srch
, (char **)attributes
, 0,
1176 DPRINTF("ldap_search_st failed");
1177 if (my_ldap_fp
) return (-1);
1181 if ((cnt
=ldap_count_entries(my_ldap_fp
, result
)) != 1)
1184 err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1187 ldap_msgfree(result
);
1192 entry
=ldap_first_entry(my_ldap_fp
, result
);
1196 ldap_msgfree(result
);
1198 err("authldap: unexpected NULL from ldap_first_entry");
1202 copy_value(my_ldap_fp
, entry
, attributes
[0], &v
, user
);
1206 DPRINTF("emailmap: empty attribute");
1207 ldap_msgfree(result
);
1211 aname
=my_ldap
.emailmap_handle_lookup
;
1215 DPRINTF("emailmap results: aname=%s, handle=%s", aname
, v
);
1217 cnt
=auth_ldap_do3(service
,
1218 aname
, v
, pass
, callback
, arg
, newpass
, user
);
1220 ldap_msgfree(result
);
1225 static int auth_ldap_do3(const char *service
,
1226 const char *attrname
,
1227 const char *user
, const char *pass
,
1228 int (*callback
)(struct authinfo
*, void *),
1229 void *arg
, const char *newpass
,
1230 const char *authaddr
)
1232 char *newpass_crypt
=0;
1233 const char *attributes
[10];
1234 struct timeval timeout
;
1236 LDAPMessage
*result
;
1241 struct authinfo auth
;
1244 char *userPassword
=0;
1245 char *cryptPassword
=0;
1252 int additionalFilter
= 0;
1253 int hasAdditionalFilter
= 0;
1255 hasAdditionalFilter
= my_ldap
.filter
!= 0;
1257 memset(&auth
, 0, sizeof(auth
));
1259 if (hasAdditionalFilter
)
1261 /* To add the additional filter, we need to add on the
1262 * additional size for "(&)" and the other filter. So
1265 additionalFilter
= strlen(my_ldap
.filter
) + 3;
1268 if ((filter
=malloc(additionalFilter
+strlen(attrname
)+strlen(user
)+
1269 (my_ldap
.domain
? strlen(my_ldap
.domain
):0)+
1270 sizeof ("(=@)"))) == 0)
1275 strcpy(filter
, "\0");
1277 if (hasAdditionalFilter
)
1279 strcat(filter
, "(&");
1280 strcat(filter
, my_ldap
.filter
);
1283 strcat(strcat(strcat(strcat(filter
, "("), attrname
), "="), user
);
1284 if ( my_ldap
.domain
&& my_ldap
.domain
[0] && strchr(user
, '@') == 0 )
1285 strcat(strcat(filter
, "@"), my_ldap
.domain
);
1286 strcat(filter
, ")");
1288 if (hasAdditionalFilter
)
1290 strcat(filter
, ")");
1293 DPRINTF("using search filter: %s", filter
);
1295 timeout
.tv_sec
=my_ldap
.timeout
;
1298 read_env("LDAP_HOMEDIR", &attributes
[0], "", 0, "homeDir");
1299 read_env(service
&& strcmp(service
, "courier") == 0
1300 ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR",
1301 &attributes
[1], "", 0, 0);
1302 read_env("LDAP_FULLNAME", &attributes
[2], "", 0, "cn");
1303 read_env("LDAP_CLEARPW", &attributes
[3], "", 0, 0);
1304 read_env("LDAP_CRYPTPW", &attributes
[4], "", 0, 0);
1305 read_env("LDAP_UID", &attributes
[5], "", 0, 0);
1306 read_env("LDAP_GID", &attributes
[6], "", 0, 0);
1307 attributes
[7]=my_ldap
.mail
;
1308 read_env("LDAP_MAILDIRQUOTA", &attributes
[8], "", 0, 0);
1314 my_ldap
.attrlist
[j
++]=attributes
[i
];
1317 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1318 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1320 my_ldap
.attrlist
[j
]=0;
1322 if (ldaperror(l_search_st(my_ldap_fp
,
1323 (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1324 filter
, (char **)my_ldap
.attrlist
, 0,
1328 DPRINTF("ldap_search_st() failed");
1331 if (my_ldap_fp
) return (-1);
1337 /* If we are more than one result, reject */
1338 if (ldap_count_entries(my_ldap_fp
,result
)!=1)
1340 DPRINTF("number of entries returned: %d (but we need exactly 1)",
1341 ldap_count_entries(my_ldap_fp
,result
));
1342 ldap_msgfree(result
);
1346 dn
= ldap_get_dn(my_ldap_fp
, result
);
1348 DPRINTF("one entry returned, DN: %s", dn
? dn
: "<null>");
1352 DPRINTF("ldap_get_dn failed");
1356 /* Get the pointer on this result */
1357 entry
=ldap_first_entry(my_ldap_fp
,result
);
1360 DPRINTF("ldap_first_entry failed");
1366 DPRINTF("after ldap_first_entry");
1369 /* print all the raw attributes */
1370 if (courier_authdebug_login_level
>= 2)
1373 BerElement
*berptr
= 0;
1375 attr
= ldap_first_attribute(my_ldap_fp
, entry
, &berptr
);
1378 DPRINTF("raw ldap entry returned:");
1385 av
= l_get_values(my_ldap_fp
, entry
, attr
);
1391 DPRINTF("| %s: %s", attr
, *ap
);
1397 attr
= ldap_next_attribute(my_ldap_fp
, entry
, berptr
);
1400 ber_free(berptr
, 0);
1403 /* Copy the directory and the password into struct */
1404 copy_value(my_ldap_fp
,entry
,attributes
[0],&homeDir
, user
);
1406 copy_value(my_ldap_fp
,entry
,attributes
[1],&mailDir
, user
);
1407 copy_value(my_ldap_fp
,entry
,attributes
[2],&cn
, user
);
1409 copy_value(my_ldap_fp
,entry
,attributes
[3],&userPassword
, user
);
1411 copy_value(my_ldap_fp
,entry
,attributes
[4],&cryptPassword
, user
);
1420 copy_value(my_ldap_fp
, entry
, attributes
[5], &p
, user
);
1422 if (sscanf(p
, "%lu", &n
) > 0)
1427 DPRINTF("au= %d",au
);
1436 copy_value(my_ldap_fp
, entry
, attributes
[6], &p
, user
);
1438 if (sscanf(p
, "%lu", &n
) > 0)
1443 DPRINTF("ag= %d",ag
);
1448 copy_value(my_ldap_fp
,entry
,attributes
[8],"a
, user
);
1450 if (homeDir
!= 0 && my_ldap
.mailroot
!= 0 && *my_ldap
.mailroot
)
1452 char *new_mailroot
=malloc(strlen(homeDir
)+
1453 strlen(my_ldap
.mailroot
)+2);
1457 perror("CRIT: authldap: malloc failed");
1462 strcat(strcat(strcpy(new_mailroot
, my_ldap
.mailroot
),
1465 homeDir
=new_mailroot
;
1471 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1475 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
], &val
,
1481 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
1490 perror("CRIT: authldap: malloc failed");
1497 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1501 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
1509 strcat(options
, ",");
1510 strcat(options
, my_ldap
.auxnames
[i
]);
1511 strcat(options
, "=");
1512 strcat(options
, val
);
1518 auth
.sysuserid
= &au
;
1519 auth
.sysgroupid
= ag
;
1520 auth
.homedir
=homeDir
;
1521 auth
.address
=authaddr
;
1523 auth
.maildir
=mailDir
;
1524 auth
.clearpasswd
=userPassword
;
1525 auth
.passwd
=cryptPassword
;
1527 auth
.options
=options
&& *options
? options
:NULL
;
1534 if (au
== 0 || ag
== 0)
1536 err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1541 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth
,
1542 userPassword
, cryptPassword
);
1546 if (my_ldap
.authbind
)
1550 bindp
=ldapconnect();
1554 DPRINTF("ldapconnect failed");
1558 #ifdef LDAP_OPT_PROTOCOL_VERSION
1559 /* Set protocol version */
1560 if (my_ldap
.protocol_version
&&
1561 ldap_set_option(bindp
, LDAP_OPT_PROTOCOL_VERSION
,
1562 (void *) & my_ldap
.protocol_version
) != LDAP_OPT_SUCCESS
)
1564 err("ldap_set_option(PROTOCOL_VERSION %d) failed",
1565 my_ldap
.protocol_version
);
1570 if(my_ldap
.tls
&& enable_tls_on(bindp
)) {
1571 err("authldaplib: LDAP_TLS enabled but I'm unable to start tls, check your config");
1581 DPRINTF("rebinding with DN '%s' to validate password", dn
);
1582 ldrc
= l_simple_bind_s(bindp
, dn
, pass
);
1586 DPRINTF("authentication bind successful");
1588 case LDAP_INVALID_CREDENTIALS
:
1589 DPRINTF("authentication bind failed, invalid credentials");
1593 DPRINTF("authentication bind failed, some other problem: %s",
1594 ldap_err2string(ldrc
));
1599 /* Drop the connection if there was a fatal
1600 error or if we are using historic LDAP v2,
1601 which didn't support rebinding on same conn */
1602 if (rc
> 0 || my_ldap
.protocol_version
== 2)
1609 if (rc
== 0 && newpass
)
1611 if ((newpass_crypt
=authcryptpasswd(newpass
,
1619 if (auth
.clearpasswd
)
1621 if (strcmp(pass
,auth
.clearpasswd
))
1623 if (courier_authdebug_login_level
>= 2)
1625 DPRINTF("supplied password '%s' does not match clearpasswd '%s'",
1626 pass
, auth
.clearpasswd
);
1630 DPRINTF("supplied password does not match clearpasswd");
1637 const char *p
=auth
.passwd
;
1641 DPRINTF("no password to compare against!");
1644 else if (authcheckpassword(pass
, p
))
1648 if (rc
== 0 && newpass
&& auth
.passwd
)
1650 if ((newpass_crypt
=authcryptpasswd(newpass
,
1658 if (rc
== 0 && newpass
)
1663 LDAPMod mod_clear
, mod_crypt
;
1664 char *mod_clear_vals
[2], *mod_crypt_vals
[2];
1668 mods
[mod_index
]= &mod_clear
;
1669 mod_clear
.mod_op
=LDAP_MOD_REPLACE
;
1670 mod_clear
.mod_type
=(char *)attributes
[3];
1671 mod_clear
.mod_values
=mod_clear_vals
;
1673 mod_clear_vals
[0]=(char *)newpass
;
1674 mod_clear_vals
[1]=NULL
;
1678 if (attributes
[4] && newpass_crypt
)
1680 mods
[mod_index
]= &mod_crypt
;
1681 mod_crypt
.mod_op
=LDAP_MOD_REPLACE
;
1682 mod_crypt
.mod_type
=(char *)attributes
[4];
1683 mod_crypt
.mod_values
=mod_crypt_vals
;
1685 mod_crypt_vals
[0]=newpass_crypt
;
1686 mod_crypt_vals
[1]=NULL
;
1696 /* On a system which uses LDAP_AUTHBIND, we probably
1697 want to use the user's credentials (bindp) rather
1698 than the search credentials (my_ldap_fp) for
1699 performing the password update. (May not always be
1700 true, ideally it would be configurable) */
1701 ld_errno
= l_modify_s(bindp
? bindp
:my_ldap_fp
, dn
, mods
);
1702 if (ld_errno
!= LDAP_SUCCESS
)
1705 DPRINTF("LDAP modify failed: %s",
1706 ldap_err2string(ld_errno
));
1712 free(newpass_crypt
);
1715 DPRINTF("before callback rc=%d",rc
);
1718 if (rc
== 0 && callback
)
1720 if (!auth
.clearpasswd
)
1721 auth
.clearpasswd
=pass
;
1722 rc
= (*callback
)(&auth
, arg
);
1724 DPRINTF("after callback rc=%d",rc
);
1728 ldap_msgfree(result
);
1729 if (options
) free(options
);
1730 if (homeDir
) free(homeDir
);
1731 if (mailDir
) free(mailDir
);
1732 if (userPassword
) free(userPassword
);
1733 if (cryptPassword
) free(cryptPassword
);
1735 if (quota
) free(quota
);
1740 ** Create an emailmap search string. I'm going to wrap this into an external
1741 ** variable, so I'll use generic coding here.
1745 const char *varname
;
1747 const char *varvalue
;
1751 static char *var_expand(const char *, const struct varlist
*);
1753 static char *emailmap_get_search_string(const char *str
, const char *email
)
1755 struct varlist vl
[3];
1756 const char *realmptr
=strrchr(email
, '@');/* Guaranteed nonNULL */
1758 static const char userid
[]="user";
1759 static const char realm
[]="realm";
1761 vl
[0].varname
=userid
;
1762 vl
[0].varname_len
=sizeof(userid
)-1;
1763 vl
[0].varvalue
=email
;
1764 vl
[0].varvalue_len
=realmptr
- email
;
1765 vl
[1].varname
=realm
;
1766 vl
[1].varname_len
=sizeof(realm
)-1;
1767 vl
[1].varvalue
=realmptr
+1;
1768 vl
[1].varvalue_len
=strlen(vl
[1].varvalue
);
1771 return (var_expand(str
, vl
));
1774 static char *var_expand(const char *str
, const struct varlist
*vl
)
1785 ** Pass 1 - count expanded string length, allocate buffer,
1786 ** Pass 2 - generate the string.
1789 for (pass
=0; pass
<2; pass
++)
1793 if ((q
=malloc(cnt
)) == NULL
)
1807 for (j
=0; vl
[j
].varname
; j
++)
1809 if (memcmp(vl
[j
].varname
, p
+1,
1810 vl
[j
].varname_len
) == 0
1811 && p
[vl
[j
].varname_len
+1] == '@')
1817 p
+= vl
[j
].varname_len
+2;
1821 memcpy(r
, vl
[j
].varvalue
,
1822 vl
[j
].varvalue_len
);
1823 r
+= vl
[j
].varvalue_len
;
1825 cnt
+= vl
[j
].varvalue_len
;
1842 void auth_ldap_enumerate( void(*cb_func
)(const char *name
,
1845 const char *homedir
,
1846 const char *maildir
,
1847 const char *options
,
1851 const char *attributes
[5];
1856 if (ldapopen()) return;
1858 read_env("LDAP_MAIL", &attributes
[0], "", 0, "mail");
1859 read_env("LDAP_UID", &attributes
[1], "", 0, 0);
1860 read_env("LDAP_GID", &attributes
[2], "", 0, 0);
1861 read_env("LDAP_HOMEDIR", &attributes
[3], "", 0, "homeDir");
1862 read_env("LDAP_MAILDIR", &attributes
[4], "", 0, 0);
1868 my_ldap
.attrlist
[j
++]=attributes
[i
];
1871 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1872 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1874 my_ldap
.attrlist
[j
]=0;
1876 DPRINTF("ldap_search: basedn='%s', filter='%s'",
1877 my_ldap
.basedn
, my_ldap
.enumerate_filter
);
1878 if ((msgid
= l_search(my_ldap_fp
, (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1879 my_ldap
.enumerate_filter
,
1880 (char **)my_ldap
.attrlist
, 0)) < 0)
1882 DPRINTF("ldap_search failed");
1886 while(1) /* process results as they come in */
1888 struct timeval timeout
;
1889 LDAPMessage
*result
;
1893 timeout
.tv_sec
=my_ldap
.timeout
;
1895 ldrc
= ldap_result(my_ldap_fp
, msgid
, 0, &timeout
, &result
);
1899 DPRINTF("error in ldap_result");
1900 ldap_msgfree(result
);
1903 DPRINTF("timeout waiting for search result");
1904 ldap_msgfree(result
);
1906 case LDAP_RES_SEARCH_ENTRY
:
1907 break; /* deal with below */
1908 case LDAP_RES_SEARCH_RESULT
:
1909 if (ldap_parse_result(my_ldap_fp
, result
, &ldrc
,
1910 NULL
, NULL
, NULL
, NULL
, 0) != LDAP_SUCCESS
)
1912 DPRINTF("ldap_parse_result failed");
1913 ldap_msgfree(result
);
1916 ldap_msgfree(result
);
1917 if (ldrc
!= LDAP_SUCCESS
)
1919 DPRINTF("ldap search failure result: %s",
1920 ldap_err2string(ldrc
));
1923 /* Search successfully completed */
1924 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1927 DPRINTF("ldap result type 0x%02X ignored", ldrc
);
1928 ldap_msgfree(result
);
1932 entry
= ldap_first_entry(my_ldap_fp
, result
);
1935 char **names
= get_values(my_ldap_fp
, entry
, attributes
[0]);
1940 entry
= ldap_next_entry(my_ldap_fp
, entry
);
1944 n
=l_count_values(names
);
1947 const char *name
= names
[0] ? names
[0] : "<null>";
1954 uid_t uid
=my_ldap
.uid
;
1955 gid_t gid
=my_ldap
.gid
;
1959 copy_value(my_ldap_fp
, entry
, attributes
[1],
1966 copy_value(my_ldap_fp
, entry
, attributes
[2],
1970 copy_value(my_ldap_fp
, entry
, attributes
[3],
1972 copy_value(my_ldap_fp
, entry
, attributes
[4],
1982 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1986 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
1992 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
2001 l_value_free(names
);
2002 perror("CRIT: auth_ldap_enumerate: malloc failed");
2007 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2011 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2018 strcat(options
, ",");
2019 strcat(options
, my_ldap
.auxnames
[i
]);
2020 strcat(options
, "=");
2021 strcat(options
, val
);
2025 for (j
= 0; j
< n
; j
++)
2029 if (name
&& homedir
)
2030 (*cb_func
)(name
, uid
, gid
, homedir
,
2031 maildir
, options
, void_arg
);
2045 l_value_free(names
);
2047 entry
= ldap_next_entry(my_ldap_fp
, entry
);
2050 ldap_msgfree(result
);