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')
396 for (i
=0; i
<ldapauth_size
; )
399 if (memcmp(p
, env
, l
) == 0 &&
400 isspace((int)(unsigned char)p
[l
]))
403 while (*p
&& *p
!= '\n' &&
404 isspace((int)(unsigned char)*p
))
409 while (i
< ldapauth_size
)
410 if (ldapauth
[i
++] == 0) break;
413 if (i
< ldapauth_size
)
433 * Function: authldap_read_config
434 * Read Configuration from the environnement table
436 * $ldap: a structure where we place information
440 static int authldap_read_config(struct ldap_info
*ldap
)
442 struct passwd
*pwent
;
447 for (i
=0; ldap
->auxoptions
&& ldap
->auxoptions
[i
]; i
++)
448 free(ldap
->auxoptions
[i
]);
449 for (i
=0; ldap
->auxnames
&& ldap
->auxnames
[i
]; i
++)
450 free(ldap
->auxnames
[i
]);
453 free(ldap
->attrlist
);
455 free(ldap
->auxnames
);
456 if (ldap
->auxoptions
)
457 free(ldap
->auxoptions
);
459 memset(ldap
,0,sizeof(struct ldap_info
));
461 if (!read_env("LDAP_URI",&ldap
->uri
,
462 "You need to specify LDAP_URI in config file",1,NULL
))
465 if (!read_env("LDAP_AUTHBIND", &p
, "", 0, ""))
469 sscanf(p
,"%d",&ldap
->authbind
);
471 if (!read_env("LDAP_BASEDN",&ldap
->basedn
,
472 "You need to specify a basedn in config file",1,NULL
))
474 if (!read_env("LDAP_BINDDN",&ldap
->binddn
,
475 "You need to specify a BINDDN in config file",0,NULL
))
477 if (!read_env("LDAP_BINDPW",&ldap
->bindpw
,
478 "You need to specify a password for the BINDDN in config file",0,NULL
))
480 if (!read_env("LDAP_MAIL",&ldap
->mail
,
481 "You need to specify a attribute for mail in config file",0,"mail"))
483 if (!read_env("LDAP_DOMAIN",&ldap
->domain
,
484 "You need to specify a domain for mail in config file",0,""))
489 if (!read_env("LDAP_GLOB_UID", &p
, "", 0, ""))
496 if (sscanf(p
, "%lu", &n
) == 1)
503 err("authldap: INVALID LDAP_GLOB_UID");
506 ldap
->uid
=pwent
->pw_uid
;
512 if (!read_env("LDAP_GLOB_GID", &p
, "", 0, ""))
519 if (sscanf(p
, "%lu", &n
) == 1)
526 err("authldap: INVALID LDAP_GLOB_GID");
529 ldap
->gid
=grent
->gr_gid
;
535 if (read_env("LDAP_TIMEOUT", &p
, "", 0, "") && p
)
537 sscanf(p
,"%d",&ldap
->timeout
);
542 if (read_env("LDAP_TLS", &p
, "", 0, "") && p
)
549 if (read_env("LDAP_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
554 ldap
->enumerate_filter
=0;
556 if (read_env("LDAP_ENUMERATE_FILTER", &p
, "", 0, "") && p
&& strlen (p
))
558 ldap
->enumerate_filter
=p
;
560 else if (ldap
->filter
)
562 ldap
->enumerate_filter
=ldap
->filter
;
566 ldap
->enumerate_filter
= malloc(strlen(ldap
->mail
)+3);
567 if (!ldap
->enumerate_filter
)
569 perror("CRIT: authldap: malloc failed");
572 sprintf((char *)ldap
->enumerate_filter
, "%s=*", ldap
->mail
);
575 ldap
->deref
= LDAP_DEREF_NEVER
;
576 ldap
->protocol_version
= 0; /* use API default */
578 if (!read_env("LDAP_DEREF", &p
, "", 0, ""))
582 #ifndef LDAP_OPT_DEREF
583 err("authldaplib: LDAP_OPT_DEREF not available, ignored");
585 if (!strcasecmp (p
, "never"))
586 ldap
->deref
= LDAP_DEREF_NEVER
;
587 else if (!strcasecmp (p
, "searching"))
588 ldap
->deref
= LDAP_DEREF_SEARCHING
;
589 else if (!strcasecmp (p
, "finding"))
590 ldap
->deref
= LDAP_DEREF_FINDING
;
591 else if (!strcasecmp (p
, "always"))
592 ldap
->deref
= LDAP_DEREF_ALWAYS
;
595 if (!read_env("LDAP_PROTOCOL_VERSION", &p
, 0, 0, 0))
600 #ifndef LDAP_OPT_PROTOCOL_VERSION
601 err("authldaplib: LDAP_OPT_PROTOCOL_VERSION not available, ignored");
604 #ifdef LDAP_VERSION_MIN
605 || lpv
< LDAP_VERSION_MIN
607 #ifdef LDAP_VERSION_MAX
608 || lpv
> LDAP_VERSION_MAX
611 err("authldaplib: illegal protocol version ignored");
613 ldap
->protocol_version
= lpv
;
616 if (!read_env("LDAP_MAILROOT",&ldap
->mailroot
,"",0,NULL
)
617 || ldap
->mailroot
== NULL
|| ldap
->mailroot
[0] == 0)
620 if (!read_env("LDAP_EMAILMAP", &ldap
->emailmap
, "", 0, "") ||
621 !read_env("LDAP_EMAILMAP_BASEDN", &ldap
->emailmap_basedn
, "", 0, "") ||
622 !read_env("LDAP_EMAILMAP_ATTRIBUTE", &ldap
->emailmap_handle
, "", 0, "")||
623 !read_env("LDAP_EMAILMAP_MAIL",
624 &ldap
->emailmap_handle_lookup
, "", 0, ""))
628 for (pass
=0; pass
<2; pass
++)
632 if ((ldap
->auxnames
=malloc((i
+1)*sizeof(char *)))
634 (ldap
->auxoptions
=malloc((i
+1)*sizeof(char *)))
637 perror("CRIT: authldap: malloc failed");
647 ldap
->auxnames
[0]=NULL
;
648 ldap
->auxoptions
[0]=NULL
;
651 if (!read_env("LDAP_AUXOPTIONS", &p
, "", 0, NULL
)
652 || p
== NULL
|| *p
== 0)
665 for (n
=0; p
[n
] && p
[n
] != ',' && p
[n
] != '='; n
++)
670 if ((ldap
->auxoptions
[i
]=malloc(n
+1)) == NULL
)
672 perror("CRIT: authldap: malloc failed");
676 memcpy(ldap
->auxoptions
[i
], p
, n
);
677 ldap
->auxoptions
[i
][n
]=0;
678 ldap
->auxoptions
[i
+1]=NULL
;
685 for (n
=0; p
[n
] && p
[n
] != ','; n
++)
692 if ((ldap
->auxnames
[i
]=
693 strdup(ldap
->auxoptions
[i
]))
696 perror("CRIT: authldap: malloc failed");
700 else if ((ldap
->auxnames
[i
]=malloc(n
+1)) == NULL
)
702 perror("CRIT: authldap: malloc failed");
707 memcpy(ldap
->auxnames
[i
], p
, n
);
708 ldap
->auxnames
[i
][n
]=0;
709 ldap
->auxnames
[i
+1]=NULL
;
717 if ((ldap
->attrlist
=malloc((i
+20)*sizeof(const char *))) == NULL
)
719 perror("CRIT: authldap: malloc failed");
726 static void get_error(LDAP
*ld
, LDAPMessage
*entry
,
728 const char *attribut
)
730 #if HAVE_LDAP_PARSE_RESULT
737 if (ldap_parse_result(ld
, entry
, &errcode
, &nmatched
,
738 &errmsg
, NULL
, NULL
, 0)
741 DPRINTF("ldap_parseresult failed");
745 if (errcode
&& errcode
!= LDAP_DECODING_ERROR
&&
746 errcode
!= LDAP_NO_RESULTS_RETURNED
)
748 DPRINTF("get_values attribute %s: %s",
750 errmsg
? errmsg
:"unknown error");
754 ldap_memfree(errmsg
);
756 ldap_memfree(nmatched
);
759 #if HAVE_LDAP_RESULT2ERROR
760 int ld_errno
= ldap_result2error(ld
,entry
,0);
761 if (ld_errno
&& ld_errno
!= LDAP_DECODING_ERROR
762 && ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
764 DPRINTF("get_values attribute %s: %s", attribut
,
765 ldap_err2string(ld_errno
));
768 if (ld
->ld_errno
!= LDAP_DECODING_ERROR
769 && ld
->ld_errno
!= LDAP_NO_RESULTS_RETURNED
)
771 DPRINTF("get_values attribute %s: %s", attribut
,
772 ldap_err2string(ld
->ld_errno
));
778 static char **get_values(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
)
781 values
=l_get_values(ld
,entry
, (char *)attribut
);
785 get_error(ld
, entry
, "get_values", attribut
);
794 * Function: copy_value
795 * Copy value from a LDAP attribute to $copy
797 * $ld: the connection with the LDAP server
798 * $entry: the entry who contains attributes
799 * $attribut: this attribut
800 * $copy: where data can go
804 static void copy_value(LDAP
*ld
, LDAPMessage
*entry
, const char *attribut
,
805 char **copy
, const char *username
)
808 values
=l_get_values(ld
,entry
, attribut
);
812 get_error(ld
, entry
, "copy_value ", attribut
);
816 /* We accept only attribute with one value */
817 else if (l_count_values(values
)>1)
819 *copy
=strdup(values
[0]);
820 fprintf(stderr
, "WARN: authldaplib: duplicate attribute %s for %s\n",
825 /* We accept only attribute with one value */
826 else if (l_count_values(values
)!=1)
832 *copy
=strdup(values
[0]);
835 DPRINTF("copy_value %s: %s",attribut
,values
[0]);
837 l_value_free(values
);
840 static struct ldap_info my_ldap
;
841 static LDAP
*my_ldap_fp
=0;
842 static LDAP
*bindp
=0; /* for checking passwords with AUTHBIND */
848 l_unbind(my_ldap_fp
);
858 static int ldaperror(int rc
)
861 if (rc
&& !LDAP_NAME_ERROR(rc
))
863 if (rc
&& !NAME_ERROR(rc
))
866 /* If there was a protocol error, close the connection */
873 /* This function takes a ldap connection and
874 * tries to enable TLS on it.
876 static int enable_tls_on(LDAP
*conn
) {
881 if (ldaperror(ldrc
=ldap_get_option (conn
,
882 LDAP_OPT_PROTOCOL_VERSION
,
886 const char *s
=ldap_err2string(ldrc
);
888 err("ldap_get_option failed: %s", s
);
892 if (version
< LDAP_VERSION3
)
894 version
= LDAP_VERSION3
;
895 (void)ldap_set_option (conn
,
896 LDAP_OPT_PROTOCOL_VERSION
,
900 if (ldaperror(ldrc
=ldap_start_tls_s(conn
, NULL
, NULL
))
903 const char *s
=ldap_err2string(ldrc
);
905 err("ldap_start_tls_s failed: %s", s
);
910 err("authldaplib: TLS not available");
915 static LDAP
*ldapconnect()
920 DPRINTF("URI: %s",my_ldap
.uri
);
921 DPRINTF("UID: %d",my_ldap
.uid
);
922 DPRINTF("GID: %d",my_ldap
.gid
);
927 DPRINTF("authldaplib: timing out after failed connection");
931 ldap_initialize(&p
, my_ldap
.uri
);
935 err("cannot connect to LDAP server (%s): %s",
936 my_ldap
.uri
, strerror(errno
));
939 #ifdef LDAP_OPT_NETWORK_TIMEOUT
940 if (my_ldap
.timeout
> 0)
941 ldap_set_option (p
, LDAP_OPT_NETWORK_TIMEOUT
, &my_ldap
.timeout
);
944 DPRINTF("ldapconnect end");
949 static int ldapopen()
953 if (my_ldap_fp
) return (0);
955 if (authldap_read_config(&my_ldap
) == 0)
957 err("authldaplib: error in LDAP configuration file, aborting");
961 my_ldap_fp
=ldapconnect();
968 #ifdef LDAP_OPT_PROTOCOL_VERSION
970 /* Set protocol version if selected */
971 if (my_ldap
.protocol_version
&&
972 ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_PROTOCOL_VERSION
,
973 (void *) & my_ldap
.protocol_version
)) != LDAP_SUCCESS
)
975 const char *s
=ldap_err2string(ldrc
);
977 err("ldap_set_option(PROTOCOL_VERSION %d) failed: %s",
978 my_ldap
.protocol_version
, s
);
983 if (my_ldap
.protocol_version
)
985 DPRINTF("selected ldap protocol version %d", my_ldap
.protocol_version
);
989 if (my_ldap
.tls
&& enable_tls_on(my_ldap_fp
))
996 #ifdef LDAP_OPT_DEREF
998 /* Set dereferencing mode */
999 if (ldaperror(ldrc
= ldap_set_option(my_ldap_fp
, LDAP_OPT_DEREF
,
1000 (void *) & my_ldap
.deref
)) != LDAP_SUCCESS
)
1002 const char *s
=ldap_err2string(ldrc
);
1004 err("ldap_set_option(DEREF) failed: %s", s
);
1011 /* Bind to server */
1012 if (courier_authdebug_login_level
>= 2)
1014 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
1015 my_ldap
.binddn
? my_ldap
.binddn
: "<null>",
1016 my_ldap
.bindpw
? my_ldap
.bindpw
: "<null>");
1020 DPRINTF("binding to LDAP server as DN '%s'",
1021 my_ldap
.binddn
? my_ldap
.binddn
: "<null>");
1024 if (ldaperror(ldrc
= l_simple_bind_s(my_ldap_fp
,
1026 my_ldap
.bindpw
)) != LDAP_SUCCESS
)
1028 const char *s
=ldap_err2string(ldrc
);
1030 err("ldap_simple_bind_s failed: %s", s
);
1038 static int auth_ldap_do(const char *, const char *, const char *,
1039 int (*)(struct authinfo
*, void *),
1040 void *arg
, const char *);
1042 int auth_ldap_changepw(const char *dummy
, const char *user
,
1044 const char *newpass
)
1046 return auth_ldap_do("authlib", user
, pass
, NULL
, NULL
, newpass
);
1050 * Function: authldapcommon
1051 * Get information from the LDAP server ($ldap) for this $user
1053 * $user: the login name
1054 * $pass: the login password (NULL if we don't want to check the pw)
1055 * callback - callback function with filled in authentication info
1056 * arg - extra argument for the callback function.
1058 * < 0 - authentication failure
1059 * > 0 - temporary failure
1060 * else return code from the callback function.
1063 int authldapcommon(const char *service
,
1064 const char *user
, const char *pass
,
1065 int (*callback
)(struct authinfo
*, void *),
1068 return (auth_ldap_do(service
, user
, pass
, callback
, arg
, NULL
));
1071 static int auth_ldap_do2(const char *service
,
1072 const char *user
, const char *pass
,
1073 int (*callback
)(struct authinfo
*, void *),
1074 void *arg
, const char *newpass
);
1076 static char *escape_str(const char *);
1078 static int auth_ldap_retry(const char *service
,
1079 const char *user
, const char *pass
,
1080 int (*callback
)(struct authinfo
*, void *),
1081 void *arg
, const char *newpass
);
1083 static int auth_ldap_do(const char *service
,
1084 const char *user
, const char *pass
,
1085 int (*callback
)(struct authinfo
*, void *),
1086 void *arg
, const char *newpass
)
1088 int rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
, newpass
);
1091 rc
=auth_ldap_retry(service
, user
, pass
, callback
, arg
,
1097 static int auth_ldap_retry(const char *service
,
1098 const char *user
, const char *pass
,
1099 int (*callback
)(struct authinfo
*, void *),
1100 void *arg
, const char *newpass
)
1108 return (auth_ldap_do2(service
,
1109 user
, pass
, callback
, arg
, newpass
));
1111 i
=auth_ldap_do2(service
, q
, pass
, callback
, arg
, newpass
);
1117 static int auth_ldap_do3(const char *service
,
1118 const char *attrname
,
1119 const char *user
, const char *pass
,
1120 int (*callback
)(struct authinfo
*, void *),
1121 void *arg
, const char *newpass
, const char *authaddr
);
1123 static char *emailmap_get_search_string(const char *str
, const char *email
);
1125 static int auth_ldap_do2(const char *service
,
1126 const char *user
, const char *pass
,
1127 int (*callback
)(struct authinfo
*, void *),
1128 void *arg
, const char *newpass
)
1132 const char *attributes
[2];
1133 LDAPMessage
*result
, *entry
;
1138 if (ldapopen()) return (1);
1140 if (my_ldap
.emailmap
[0] == 0 || strchr(user
, '@') == NULL
)
1141 return (auth_ldap_do3(service
, my_ldap
.mail
,
1142 user
, pass
, callback
, arg
, newpass
,
1144 /* Mapping is not enabled */
1146 srch
=emailmap_get_search_string(my_ldap
.emailmap
, user
);
1150 perror("CRIT: authldaplib: malloc");
1153 DPRINTF("using emailmap search: %s", srch
);
1155 tv
.tv_sec
=my_ldap
.timeout
;
1158 attributes
[0]=my_ldap
.emailmap_handle
;
1160 if (!attributes
[0][0])
1161 attributes
[0]="handle";
1164 if (ldaperror(l_search_st(my_ldap_fp
,
1165 (char *)(my_ldap
.emailmap_basedn
[0] ?
1166 my_ldap
.emailmap_basedn
1169 srch
, (char **)attributes
, 0,
1175 DPRINTF("ldap_search_st failed");
1176 if (my_ldap_fp
) return (-1);
1180 if ((cnt
=ldap_count_entries(my_ldap_fp
, result
)) != 1)
1185 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 ** Escape a string with special LDAP characters. Returns NULL if the original
1741 ** string does not have any special LDAP characters (so we don't allocate
1742 ** memory unless absolutely necessary).
1745 static char *escape_str(const char *user
)
1751 for (i
=0, p
=user
; *p
; p
++)
1752 if (strchr("*()\\", *p
))
1756 return NULL
; /* No need to escape anything */
1758 q
=malloc(strlen(user
)+i
+1);
1766 for (r
=q
, p
=user
; *p
; p
++)
1768 if (strchr("*()\\", *p
))
1777 ** Create an emailmap search string. I'm going to wrap this into an external
1778 ** variable, so I'll use generic coding here.
1782 const char *varname
;
1784 const char *varvalue
;
1788 static char *var_expand(const char *, const struct varlist
*);
1790 static char *emailmap_get_search_string(const char *str
, const char *email
)
1792 struct varlist vl
[3];
1793 const char *realmptr
=strrchr(email
, '@');/* Guaranteed nonNULL */
1795 static const char userid
[]="user";
1796 static const char realm
[]="realm";
1798 vl
[0].varname
=userid
;
1799 vl
[0].varname_len
=sizeof(userid
)-1;
1800 vl
[0].varvalue
=email
;
1801 vl
[0].varvalue_len
=realmptr
- email
;
1802 vl
[1].varname
=realm
;
1803 vl
[1].varname_len
=sizeof(realm
)-1;
1804 vl
[1].varvalue
=realmptr
+1;
1805 vl
[1].varvalue_len
=strlen(vl
[1].varvalue
);
1808 return (var_expand(str
, vl
));
1811 static char *var_expand(const char *str
, const struct varlist
*vl
)
1822 ** Pass 1 - count expanded string length, allocate buffer,
1823 ** Pass 2 - generate the string.
1826 for (pass
=0; pass
<2; pass
++)
1830 if ((q
=malloc(cnt
)) == NULL
)
1844 for (j
=0; vl
[j
].varname
; j
++)
1846 if (memcmp(vl
[j
].varname
, p
+1,
1847 vl
[j
].varname_len
) == 0
1848 && p
[vl
[j
].varname_len
+1] == '@')
1854 p
+= vl
[j
].varname_len
+2;
1858 memcpy(r
, vl
[j
].varvalue
,
1859 vl
[j
].varvalue_len
);
1860 r
+= vl
[j
].varvalue_len
;
1862 cnt
+= vl
[j
].varvalue_len
;
1879 void auth_ldap_enumerate( void(*cb_func
)(const char *name
,
1882 const char *homedir
,
1883 const char *maildir
,
1884 const char *options
,
1888 const char *attributes
[5];
1893 if (ldapopen()) return;
1895 read_env("LDAP_MAIL", &attributes
[0], "", 0, "mail");
1896 read_env("LDAP_UID", &attributes
[1], "", 0, 0);
1897 read_env("LDAP_GID", &attributes
[2], "", 0, 0);
1898 read_env("LDAP_HOMEDIR", &attributes
[3], "", 0, "homeDir");
1899 read_env("LDAP_MAILDIR", &attributes
[4], "", 0, 0);
1905 my_ldap
.attrlist
[j
++]=attributes
[i
];
1908 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
1909 my_ldap
.attrlist
[j
++]=my_ldap
.auxoptions
[i
];
1911 my_ldap
.attrlist
[j
]=0;
1913 DPRINTF("ldap_search: basedn='%s', filter='%s'",
1914 my_ldap
.basedn
, my_ldap
.enumerate_filter
);
1915 if ((msgid
= l_search(my_ldap_fp
, (char *)my_ldap
.basedn
,LDAP_SCOPE_SUBTREE
,
1916 my_ldap
.enumerate_filter
,
1917 (char **)my_ldap
.attrlist
, 0)) < 0)
1919 DPRINTF("ldap_search failed");
1923 while(1) /* process results as they come in */
1925 struct timeval timeout
;
1926 LDAPMessage
*result
;
1930 timeout
.tv_sec
=my_ldap
.timeout
;
1932 ldrc
= ldap_result(my_ldap_fp
, msgid
, 0, &timeout
, &result
);
1936 DPRINTF("error in ldap_result");
1937 ldap_msgfree(result
);
1940 DPRINTF("timeout waiting for search result");
1941 ldap_msgfree(result
);
1943 case LDAP_RES_SEARCH_ENTRY
:
1944 break; /* deal with below */
1945 case LDAP_RES_SEARCH_RESULT
:
1946 if (ldap_parse_result(my_ldap_fp
, result
, &ldrc
,
1947 NULL
, NULL
, NULL
, NULL
, 0) != LDAP_SUCCESS
)
1949 DPRINTF("ldap_parse_result failed");
1950 ldap_msgfree(result
);
1953 ldap_msgfree(result
);
1954 if (ldrc
!= LDAP_SUCCESS
)
1956 DPRINTF("ldap search failure result: %s",
1957 ldap_err2string(ldrc
));
1960 /* Search successfully completed */
1961 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1964 DPRINTF("ldap result type 0x%02X ignored", ldrc
);
1965 ldap_msgfree(result
);
1969 entry
= ldap_first_entry(my_ldap_fp
, result
);
1972 char **names
= get_values(my_ldap_fp
, entry
, attributes
[0]);
1977 entry
= ldap_next_entry(my_ldap_fp
, entry
);
1981 n
=l_count_values(names
);
1984 const char *name
= names
[0] ? names
[0] : "<null>";
1991 uid_t uid
=my_ldap
.uid
;
1992 gid_t gid
=my_ldap
.gid
;
1996 copy_value(my_ldap_fp
, entry
, attributes
[1],
2003 copy_value(my_ldap_fp
, entry
, attributes
[2],
2007 copy_value(my_ldap_fp
, entry
, attributes
[3],
2009 copy_value(my_ldap_fp
, entry
, attributes
[4],
2019 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2023 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2029 j
+= 2 + strlen(my_ldap
.auxnames
[i
]) +
2038 perror("CRIT: auth_ldap_enumerate: malloc failed");
2043 for (i
=0; my_ldap
.auxoptions
[i
]; i
++)
2047 copy_value(my_ldap_fp
, entry
, my_ldap
.auxoptions
[i
],
2054 strcat(options
, ",");
2055 strcat(options
, my_ldap
.auxnames
[i
]);
2056 strcat(options
, "=");
2057 strcat(options
, val
);
2061 for (j
= 0; j
< n
; j
++)
2065 if (name
&& homedir
)
2066 (*cb_func
)(name
, uid
, gid
, homedir
,
2067 maildir
, options
, void_arg
);
2081 l_value_free(names
);
2083 entry
= ldap_next_entry(my_ldap_fp
, entry
);
2086 ldap_msgfree(result
);