2 ** Copyright 2016 Double Precision, Inc. See COPYING for
3 ** distribution information.
7 #include "courier_auth_config.h"
36 #include "authldaprc.h"
37 #include "courierauthdebug.h"
40 #include "authconfigfile.h"
43 #ifndef LDAP_OPT_SUCCESS
44 #define LDAP_OPT_SUCCESS LDAP_SUCCESS
48 ** Main connection to the LDAP server, and a separate connection for the
49 ** LDAP_AUTHBIND option.
52 class ldap_connection
{
57 ldap_connection() : connection(0) {}
58 ~ldap_connection() { disconnect(); }
60 bool connected() const { return connection
!= 0; }
71 static bool ok(const char *method
, int rc
)
73 if (rc
== 0 || LDAP_NAME_ERROR(rc
))
76 courier_auth_err("%s failed: %s", method
,
81 bool bind(const std::string
&userid
,
82 const std::string
&password
)
84 std::vector
<char> buffer(password
.begin(), password
.end());
87 cred
.bv_len
=buffer
.size();
88 cred
.bv_val
=&buffer
[0];
91 ok("ldap_sasl_bind_s",
92 ldap_sasl_bind_s(connection
, userid
.c_str(),
99 ok("ldap_sasl_bind_s",
100 ldap_sasl_bind_s(connection
, userid
.c_str(),
106 ldap_connection main_connection
, bind_connection
;
109 // Loaded and parsed authldaprc configuration file.
111 class authldaprc_file
: public courier::auth::config_file
{
115 int protocol_version
;
123 std::string ldap_uri
, ldap_binddn
, ldap_bindpw
, ldap_basedn
;
126 std::vector
<std::string
> auxoptions
, auxnames
;
137 ** There's a memory leak in OpenLDAP 1.2.11, presumably in earlier versions
138 ** too. See http://www.OpenLDAP.org/its/index.cgi?findid=864 for more
139 ** information. To work around the bug, the first time a connection fails
140 ** we stop trying for 60 seconds. After 60 seconds we kill the process,
141 ** and let the parent process restart it.
143 ** We'll control this behavior via LDAP_MEMORY_LEAK. Set it to ZERO to turn
144 ** off this behavior (whenever OpenLDAP gets fixed).
147 static time_t ldapfailflag
=0;
149 static void ldapconnfailure()
151 const char *p
=getenv("LDAP_MEMORY_LEAK");
155 #ifdef LDAP_VENDOR_NAME
156 #ifdef LDAP_VENDOR_VERSION
157 #define DO_OPENLDAP_CHECK
161 #ifdef DO_OPENLDAP_CHECK
163 /* It's supposed to be fixed in 20019 */
165 if (strcmp(LDAP_VENDOR_NAME
, "OpenLDAP") == 0 &&
166 LDAP_VENDOR_VERSION
< 20019)
175 if (atoi(p
) && !ldapfailflag
)
182 static int ldapconncheck()
191 if (t
>= ldapfailflag
)
196 authldaprc_file::authldaprc_file()
197 : config_file(AUTHLDAPRC
)
201 bool authldaprc_file::do_load()
205 // Frequently-accessed variables.
207 if (!config("LDAP_TIMEOUT", timeout
, false, "5") ||
208 !config("LDAP_TLS", tls
, false, "0"))
213 if (!config("LDAP_URI", ldap_uri
, true))
220 std::string deref_setting
;
222 config("LDAP_DEREF", deref_setting
, false, "");
224 for (std::string::iterator p
=deref_setting
.begin();
225 p
!= deref_setting
.end(); ++p
)
228 #ifdef LDAP_OPT_DEREF
230 ldap_deref
=LDAP_DEREF_NEVER
;
232 if (deref_setting
== "never")
233 ldap_deref
= LDAP_DEREF_NEVER
;
234 else if (deref_setting
== "searching")
235 ldap_deref
= LDAP_DEREF_SEARCHING
;
236 else if (deref_setting
== "finding")
237 ldap_deref
= LDAP_DEREF_FINDING
;
238 else if (deref_setting
== "always")
239 ldap_deref
= LDAP_DEREF_ALWAYS
;
240 else if (deref_setting
!= "")
243 courier_auth_err("authldap: INVALID LDAP_OPT_DEREF");
249 std::string uid_str
, gid_str
;
251 config("LDAP_GLOB_UID", uid_str
, false);
252 config("LDAP_GLOB_GID", gid_str
, false);
254 if (!uid_str
.empty())
256 std::istringstream
i(uid_str
);
262 struct passwd
*pwent
=getpwnam(uid_str
.c_str());
266 courier_auth_err("authldap: INVALID LDAP_GLOB_UID");
276 if (!gid_str
.empty())
278 std::istringstream
i(uid_str
);
284 struct group
*grent
=getgrnam(gid_str
.c_str());
288 courier_auth_err("authldap: INVALID LDAP_GLOB_GID");
298 if (!config("LDAP_AUTHBIND", authbind
, false, "0")
299 || !config("LDAP_INITBIND", initbind
, false, "0")
300 || !config("LDAP_BASEDN", ldap_basedn
, true))
305 if (!config("LDAP_BINDDN", ldap_binddn
, true) ||
306 !config("LDAP_BINDPW", ldap_bindpw
, true))
310 if (!config("LDAP_PROTOCOL_VERSION", protocol_version
, false, "0"))
313 if (protocol_version
)
315 #ifndef LDAP_OPT_PROTOCOL_VERSION
316 courier_auth_err("authldaplib: LDAP_OPT_PROTOCOL_VERSION ignored");
320 #ifdef LDAP_VERSION_MIN
321 || protocol_version
< LDAP_VERSION_MIN
323 #ifdef LDAP_VERSION_MAX
324 || protocol_version
> LDAP_VERSION_MAX
329 courier_auth_err("authldaplib: LDAP_PROTOCOL_VERSION not supported");
334 std::string auxoptions_str
;
336 config("LDAP_AUXOPTIONS", auxoptions_str
, "");
338 std::string::iterator p
=auxoptions_str
.begin();
340 while (p
!= auxoptions_str
.end())
348 std::string::iterator q
=p
;
350 p
=std::find(p
, auxoptions_str
.end(), ',');
352 std::string
auxoption(q
, p
);
355 q
=std::find(auxoption
.begin(), auxoption
.end(), '=');
357 if (q
!= auxoption
.end())
359 auxname
=std::string(q
+1, auxoption
.end());
360 auxoption
=std::string(auxoption
.begin(), q
);
363 auxoptions
.push_back(auxoption
);
364 auxnames
.push_back(auxname
);
370 void authldaprc_file::do_reload()
372 // File changed, try to load it again.
374 authldaprc_file new_file
;
376 if (new_file
.load(true))
379 DPRINTF("authldap: reloaded %s", filename
);
381 // If we reloaded the file, close the
382 // connections, so they can be reopened using
385 main_connection
.close();
386 bind_connection
.close();
390 static authldaprc_file authldaprc
;
393 bool ldap_connection::enable_tls()
397 if (!ok("ldap_get_option",
398 ldap_get_option(connection
, LDAP_OPT_PROTOCOL_VERSION
,
402 if (version
< LDAP_VERSION3
)
404 version
= LDAP_VERSION3
;
405 (void)ldap_set_option (connection
,
406 LDAP_OPT_PROTOCOL_VERSION
,
410 if (!ok("ldap_start_tls_s",
411 ldap_start_tls_s(connection
, NULL
, NULL
)))
419 bool ldap_connection::enable_tls()
421 courier_auth_err("authldaplib: TLS not available");
426 bool ldap_connection::connect()
428 if (connected()) return true;
430 DPRINTF("authldaplib: connecting to %s", authldaprc
.ldap_uri
.c_str());
434 DPRINTF("authldaplib: timing out after failed connection");
438 ldap_initialize(&connection
, authldaprc
.ldap_uri
.c_str());
440 if (connection
==NULL
)
442 courier_auth_err("cannot connect to LDAP server (%s): %s",
443 authldaprc
.ldap_uri
.c_str(), strerror(errno
));
446 #ifdef LDAP_OPT_NETWORK_TIMEOUT
447 else if (authldaprc
.timeout
> 0)
449 DPRINTF("timeout set to %d", authldaprc
.timeout
);
450 ldap_set_option (connection
, LDAP_OPT_NETWORK_TIMEOUT
, &authldaprc
.timeout
);
454 #ifdef LDAP_OPT_PROTOCOL_VERSION
456 if (authldaprc
.protocol_version
&&
457 !ok("ldap_set_option",
458 ldap_set_option(connection
,
459 LDAP_OPT_PROTOCOL_VERSION
,
460 (void *) &authldaprc
.protocol_version
)))
466 if (authldaprc
.protocol_version
)
468 DPRINTF("selected ldap protocol version %d", authldaprc
.protocol_version
);
472 if (authldaprc
.tls
&& !enable_tls())
478 #ifdef LDAP_OPT_DEREF
479 if (!ok("ldap_set_option",
480 ldap_set_option(connection
, LDAP_OPT_DEREF
,
481 (void *)&authldaprc
.ldap_deref
)))
487 if (!deref_setting
.empty())
489 courier_auth_err("authldaplib: LDAP_OPT_DEREF not available, ignored");
496 void ldap_connection::disconnect()
502 void ldap_connection::close()
504 if (connection
== NULL
)
507 ldap_unbind_ext(connection
, 0, 0);
511 static int ldapopen()
513 if (main_connection
.connected()) return 0;
515 if (!main_connection
.connect())
518 if (authldaprc
.initbind
)
521 if (courier_authdebug_login_level
>= 2)
523 DPRINTF("binding to LDAP server as DN '%s', password '%s'",
524 authldaprc
.ldap_binddn
.empty() ? "<null>"
525 : authldaprc
.ldap_binddn
.c_str(),
526 authldaprc
.ldap_bindpw
.empty() ? "<null>"
527 : authldaprc
.ldap_bindpw
.c_str());
531 DPRINTF("binding to LDAP server as DN '%s'",
532 authldaprc
.ldap_binddn
.empty() ? "<null>"
533 : authldaprc
.ldap_binddn
.c_str());
536 if (!main_connection
.bind(authldaprc
.ldap_binddn
,
537 authldaprc
.ldap_bindpw
))
547 class authldaprc_attributes
{
551 std::map
<std::string
, std::string
*> attributes
;
553 std::string
attribute(const char *name
,
554 const char *default_value
,
555 std::string
&return_value
)
559 authldaprc
.config(name
, value
, false, default_value
);
562 attributes
[value
]=&return_value
;
567 class authldaprc_attribute_vector
: public std::vector
<std::string
> {
571 authldaprc_attribute_vector(const std::map
<std::string
, std::string
*>
574 for (std::map
<std::string
, std::string
*>::const_iterator
575 p
=attributes
.begin(); p
!= attributes
.end(); ++p
)
582 class authldaprc_search_attributes
{
584 std::vector
<std::string
> copy_buffer
;
588 std::vector
<char *> all_attributes_ptr
;
590 authldaprc_search_attributes(const std::vector
<std::string
> &attributes
)
591 : copy_buffer(attributes
)
593 for (std::vector
<std::string
>::iterator
594 p
=copy_buffer
.begin();
595 p
!= copy_buffer
.end(); ++p
)
601 all_attributes_ptr
.push_back(& (*p
)[0]);
604 all_attributes_ptr
.push_back(0);
607 char **search_attributes()
609 return &all_attributes_ptr
[0];
613 class authldaprc_search_result
: authldaprc_search_attributes
{
620 authldaprc_search_result(ldap_connection
&conn
,
621 const std::string
&basedn
,
622 const std::string
&query
,
623 const std::vector
<std::string
> &attributes
,
624 const struct timeval
&timeout
)
625 : authldaprc_search_attributes(attributes
),
626 ptr(NULL
), finished(false)
628 struct timeval timeout_copy
=timeout
;
630 if (!conn
.connect() ||
631 !conn
.ok("ldap_search_ext_s",
632 ldap_search_ext_s(conn
.connection
,
645 || !conn
.ok("ldap_search_ext_s",
646 ldap_search_ext_s(conn
.connection
,
661 authldaprc_search_result(ldap_connection
&conn
,
664 const struct timeval
&timeout
)
665 :authldaprc_search_attributes(std::vector
<std::string
>()),
666 ptr(NULL
), finished(false)
670 struct timeval timeout_copy
=timeout
;
672 int rc
=ldap_result(conn
.connection
, msgid
, all
? 1:0,
679 DPRINTF("ldap_result() failed");
684 DPRINTF("ldap_result() timed out");
688 case LDAP_RES_SEARCH_ENTRY
:
689 break; /* deal with below */
690 case LDAP_RES_SEARCH_RESULT
:
691 if (ldap_parse_result(conn
.connection
, ptr
,
693 NULL
, NULL
, NULL
, NULL
,
696 DPRINTF("ldap_parse_result failed");
703 if (rc
!= LDAP_SUCCESS
)
705 DPRINTF("search failed: %s",
706 ldap_err2string(rc
));
712 DPRINTF("ldap_result(): ignored 0x%02X status",
722 bool operator!() const
727 operator bool() const
732 ~authldaprc_search_result()
739 static std::vector
<std::string
>
740 authldap_entry_values(LDAP
*connection
, LDAPMessage
*msg
,
741 const std::string
&attrname
)
743 std::vector
<std::string
> values
;
745 struct berval
**p
=ldap_get_values_len(connection
, msg
,
751 size_t n
=ldap_count_values_len(p
);
755 for (size_t i
=0; i
<n
; i
++)
758 reinterpret_cast<const char *>(p
[i
]->bv_val
);
760 values
.push_back(std::string(ptr
, ptr
+p
[i
]->bv_len
));
763 ldap_value_free_len(p
);
768 class authldap_get_values
{
776 authldap_get_values(LDAP
*connectionArg
,
777 LDAPMessage
*entryArg
,
778 const std::string
&contextArg
)
779 : connection(connectionArg
),
785 bool operator()(const std::string
&attrname
,
788 std::vector
<std::string
> values
=
789 authldap_entry_values(connection
, entry
, attrname
);
794 if (values
.size() > 1)
797 "WARN: authldaplib: duplicate attribute %s for %s\n",
806 std::string
options()
810 std::ostringstream options
;
811 const char *options_sep
="";
813 for (i
=0; i
<authldaprc
.auxoptions
.size(); ++i
)
817 if (operator()(authldaprc
.auxoptions
[i
], value
)
820 options
<< options_sep
821 << authldaprc
.auxnames
[i
]
827 return options
.str();
831 static void cpp_auth_ldap_enumerate( void(*cb_func
)(const char *name
,
844 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
848 std::string mail_field
, uid_field
, gid_field
,
849 homedir_field
, maildir_field
;
851 authldaprc
.config("LDAP_MAIL", mail_field
, false, "mail");
852 authldaprc
.config("LDAP_UID", uid_field
, false);
853 authldaprc
.config("LDAP_GID", gid_field
, false);
854 authldaprc
.config("LDAP_HOMEDIR", homedir_field
, false, "homeDir");
855 authldaprc
.config("LDAP_MAILDIR", maildir_field
, false);
857 std::vector
<std::string
> attribute_vector
;
859 attribute_vector
.push_back(mail_field
);
860 attribute_vector
.push_back(uid_field
);
861 attribute_vector
.push_back(gid_field
);
862 attribute_vector
.push_back(homedir_field
);
863 attribute_vector
.push_back(maildir_field
);
865 for (size_t i
=0; i
<authldaprc
.auxoptions
.size(); i
++)
867 attribute_vector
.push_back(authldaprc
.auxoptions
[i
]);
870 std::string enumerate_filter
;
872 authldaprc
.config("LDAP_ENUMERATE_FILTER", enumerate_filter
, false);
874 if (enumerate_filter
.empty())
878 authldaprc
.config("LDAP_FILTER", filter
, false);
882 enumerate_filter
=filter
;
888 authldaprc
.config("LDAP_MAIL", s
, false);
890 enumerate_filter
= s
+ "=*";
894 DPRINTF("ldap_search: basedn='%s', filter='%s'",
895 authldaprc
.ldap_basedn
.c_str(), enumerate_filter
.c_str());
897 authldaprc_search_attributes
search_attributes(attribute_vector
);
903 if (ldap_search_ext(main_connection
.connection
,
904 authldaprc
.ldap_basedn
.c_str(),
906 enumerate_filter
.c_str(),
907 search_attributes
.search_attributes(),
909 NULL
, NULL
, &tv
, 1000000, &msgid
) < 0)
911 DPRINTF("ldap_search_ext failed");
915 /* Process results */
919 struct timeval timeout
;
922 timeout
.tv_sec
=authldaprc
.timeout
;
925 authldaprc_search_result
search_result(main_connection
,
930 if (search_result
.finished
)
936 entry
= ldap_first_entry(main_connection
.connection
, search_result
.ptr
);
940 std::vector
<std::string
>
941 names
=authldap_entry_values(main_connection
.connection
,
947 entry
= ldap_next_entry(main_connection
.connection
, entry
);
951 size_t n
=names
.size();
955 std::string uid_s
, gid_s
, homedir
, maildir
;
956 uid_t uid
=authldaprc
.uid
;
957 gid_t gid
=authldaprc
.gid
;
960 get_value(main_connection
.connection
, entry
,
963 if (!uid_field
.empty())
964 get_value(uid_field
, uid_s
);
966 if (!gid_field
.empty())
968 get_value(gid_field
, gid_s
);
971 get_value(homedir_field
, homedir
);
972 get_value(maildir_field
, maildir
);
975 std::istringstream(uid_s
)
979 std::istringstream(gid_s
)
982 std::string options
=get_value
.options();
984 for (size_t j
=0; j
< n
; j
++)
986 if (!homedir
.empty())
987 (*cb_func
)(names
[j
].c_str(),
998 entry
= ldap_next_entry(main_connection
.connection
, entry
);
1003 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1006 static void cpp_authldapclose()
1008 main_connection
.disconnect();
1009 bind_connection
.disconnect();
1012 class authldap_lookup
: private authldaprc_attributes
{
1014 struct authinfo auth
;
1015 const char *service
;
1016 std::string attrname
;
1019 const char *newpass
;
1020 const char *authaddr
;
1023 authldap_lookup(const char *serviceArg
,
1024 const std::string
&attrnameArg
,
1025 const std::string
&userArg
,
1026 const char *passArg
,
1027 const char *newpassArg
,
1028 const char *authaddrArg
);
1030 int operator()(int (*callback
)(struct authinfo
*, void *), void *arg
);
1033 int verify_password(const std::string
&dn
);
1034 int verify_password_myself(const std::string
&dn
);
1035 int verify_password_authbind(const std::string
&dn
);
1038 authldap_lookup::authldap_lookup(const char *serviceArg
,
1039 const std::string
&attrnameArg
,
1040 const std::string
&userArg
,
1041 const char *passArg
,
1042 const char *newpassArg
,
1043 const char *authaddrArg
)
1044 : service(serviceArg
),
1045 attrname(attrnameArg
),
1048 newpass(newpassArg
),
1049 authaddr(authaddrArg
)
1053 int authldap_lookup::operator()(int (*callback
)(struct authinfo
*, void *),
1056 struct timeval timeout
;
1062 std::string homeDir
, mailDir
, userPassword
,
1072 std::ostringstream query
;
1076 authldaprc
.config("LDAP_FILTER", filter
, false);
1078 if (!filter
.empty())
1080 query
<< "(&" << filter
;
1083 query
<< "(" << attrname
<< "=" << user
;
1087 authldaprc
.config("LDAP_DOMAIN", domain
, false);
1089 if (!domain
.empty() &&
1090 std::find(user
.begin(), user
.end(), '@') == user
.end())
1091 query
<< "@" << domain
;
1094 if (!filter
.empty())
1097 std::string query_str
=query
.str();
1099 DPRINTF("Query: %s", query_str
.c_str());
1101 timeout
.tv_sec
=authldaprc
.timeout
;
1104 attribute("LDAP_HOMEDIR", "homeDir", homeDir
);
1105 attribute(service
&& strcmp(service
, "courier") == 0
1106 ? "LDAP_DEFAULTDELIVERY":"LDAP_MAILDIR", 0, mailDir
);
1107 attribute("LDAP_FULLNAME", 0, cn
);
1108 std::string clearpw_value
=attribute("LDAP_CLEARPW", 0, userPassword
);
1109 std::string cryptpw_value
=attribute("LDAP_CRYPTPW", 0, cryptPassword
);
1110 attribute("LDAP_UID", 0, uidNumber
);
1111 attribute("LDAP_GID", 0, gidNumber
);
1112 attribute("LDAP_MAILDIRQUOTA", 0, quota
);
1114 authldaprc_attribute_vector
all_attributes(attributes
);
1116 for (size_t i
=0; i
<authldaprc
.auxoptions
.size(); i
++)
1118 all_attributes
.push_back(authldaprc
.auxoptions
[i
]);
1121 authldaprc_search_result
result(main_connection
,
1122 authldaprc
.ldap_basedn
,
1127 int n_entries
=ldap_count_entries(main_connection
.connection
, result
.ptr
);
1133 DPRINTF("Not found");
1137 DPRINTF("Returned multiple entries (%d)", n_entries
);
1142 char *dn_p
= ldap_get_dn(main_connection
.connection
, result
.ptr
);
1144 DPRINTF("Returned DN: %s", dn_p
? dn_p
: "<null>");
1148 DPRINTF("ldap_get_dn failed");
1155 /* Get the pointer on this result */
1156 entry
=ldap_first_entry(main_connection
.connection
, result
.ptr
);
1159 DPRINTF("ldap_first_entry failed");
1163 /* print all the raw attributes */
1164 if (courier_authdebug_login_level
>= 2)
1166 BerElement
*berptr
= 0;
1168 ldap_first_attribute(main_connection
.connection
, entry
, &berptr
);
1172 std::vector
<std::string
>
1173 values
=authldap_entry_values(main_connection
.connection
,
1176 for (size_t i
=0; i
<values
.size(); ++i
)
1177 DPRINTF(" %s: %s", attr
, values
[i
].c_str());
1180 attr
= ldap_next_attribute(main_connection
.connection
, entry
,
1184 ber_free(berptr
, 0);
1187 authldap_get_values
get_value(main_connection
.connection
, entry
, dn
.c_str());
1189 for (std::map
<std::string
, std::string
*>::iterator
1190 p
=attributes
.begin(); p
!= attributes
.end(); ++p
)
1192 get_value(p
->first
, *p
->second
);
1197 if (!uidNumber
.empty())
1199 std::istringstream(uidNumber
) >> au
;
1202 if (!gidNumber
.empty())
1204 std::istringstream(gidNumber
) >> ag
;
1207 std::string mailroot
;
1209 authldaprc
.config("LDAP_MAILROOT", mailroot
, false);
1211 if (!homeDir
.empty() && !mailroot
.empty())
1213 homeDir
= mailroot
+ "/" + homeDir
;
1216 std::string options
=get_value
.options();
1218 memset(&auth
, 0, sizeof(auth
));
1220 auth
.sysuserid
= &au
;
1221 auth
.sysgroupid
= ag
;
1222 auth
.homedir
=homeDir
.c_str();
1223 auth
.address
=authaddr
;
1224 auth
.fullname
=cn
.c_str();
1226 if (!mailDir
.empty())
1227 auth
.maildir
=mailDir
.c_str();
1229 if (!userPassword
.empty())
1230 auth
.clearpasswd
=userPassword
.c_str();
1232 if (!cryptPassword
.empty())
1233 auth
.passwd
=cryptPassword
.c_str();
1236 auth
.quota
=quota
.c_str();
1238 if (!options
.empty())
1239 auth
.options
=options
.c_str();
1243 if (au
== 0 || ag
== 0)
1245 courier_auth_err("authldaplib: refuse to authenticate %s: uid=%d, gid=%d (zero uid or gid not permitted)",
1246 user
.c_str(), au
, ag
);
1250 courier_authdebug_authinfo("DEBUG: authldaplib: ", &auth
,
1251 userPassword
.c_str(),
1252 cryptPassword
.c_str());
1255 rc
=verify_password(dn
);
1257 std::string newpass_crypt
;
1259 if (rc
== 0 && newpass
)
1261 char *p
=authcryptpasswd(newpass
, auth
.passwd
);
1274 LDAPMod mod_clear
, mod_crypt
;
1275 char *mod_clear_vals
[2], *mod_crypt_vals
[2];
1277 std::vector
<char> clearpw_buffer
, cryptpw_buffer
;
1279 if (!clearpw_value
.empty() && auth
.clearpasswd
)
1281 clearpw_buffer
.insert(clearpw_buffer
.end(),
1282 clearpw_value
.begin(),
1283 clearpw_value
.end());
1285 clearpw_buffer
.push_back(0);
1287 mods
[mod_index
]= &mod_clear
;
1288 mod_clear
.mod_op
=LDAP_MOD_REPLACE
;
1289 mod_clear
.mod_type
=&clearpw_buffer
[0];
1290 mod_clear
.mod_values
=mod_clear_vals
;
1292 DPRINTF("Modify: %s", mod_clear
.mod_type
);
1294 mod_clear_vals
[0]=(char *)newpass
;
1295 mod_clear_vals
[1]=NULL
;
1299 if (!cryptpw_value
.empty() &&
1300 !newpass_crypt
.empty() && auth
.passwd
)
1302 cryptpw_buffer
.insert(cryptpw_buffer
.end(),
1303 cryptpw_value
.begin(),
1304 cryptpw_value
.end());
1306 cryptpw_buffer
.push_back(0);
1308 mods
[mod_index
]= &mod_crypt
;
1309 mod_crypt
.mod_op
=LDAP_MOD_REPLACE
;
1310 mod_crypt
.mod_type
=&cryptpw_buffer
[0];
1311 mod_crypt
.mod_values
=mod_crypt_vals
;
1313 DPRINTF("Modify: %s", mod_crypt
.mod_type
);
1315 newpass_crypt
.push_back(0);
1316 mod_crypt_vals
[0]=&newpass_crypt
[0];
1317 mod_crypt_vals
[1]=NULL
;
1327 ** Use the user connection for updating the password.
1331 ldap_modify_ext_s(bind_connection
.connected()
1332 ? bind_connection
.connection
1333 : main_connection
.connection
,
1337 if (ld_errno
!= LDAP_SUCCESS
)
1340 DPRINTF("Password update failed: %s",
1341 ldap_err2string(ld_errno
));
1346 if (rc
== 0 && callback
)
1348 if (!auth
.clearpasswd
)
1349 auth
.clearpasswd
=pass
;
1350 rc
= (*callback
)(&auth
, arg
);
1356 int authldap_lookup::verify_password(const std::string
&dn
)
1361 if (authldaprc
.authbind
)
1362 return verify_password_authbind(dn
);
1364 return verify_password_myself(dn
);
1367 int authldap_lookup::verify_password_authbind(const std::string
&dn
)
1369 if (!bind_connection
.connect())
1372 if (!bind_connection
.bind(dn
, pass
))
1374 bind_connection
.close();
1378 if (authldaprc
.protocol_version
== 2)
1380 // protocol version 2 does not allow rebinds.
1382 bind_connection
.close();
1388 int authldap_lookup::verify_password_myself(const std::string
&dn
)
1390 if (auth
.clearpasswd
)
1392 if (strcmp(pass
, auth
.clearpasswd
))
1394 if (courier_authdebug_login_level
>= 2)
1396 DPRINTF("Password for %s: '%s' does not match clearpasswd '%s'",
1397 dn
.c_str(), pass
, auth
.clearpasswd
);
1401 DPRINTF("Password for %s does not match",
1409 const char *p
=auth
.passwd
;
1413 DPRINTF("Missing password in LDAP!");
1417 if (authcheckpassword(pass
, p
))
1419 DPRINTF("Password for %s does not match",
1429 ** Replace keywords in the emailmap string.
1432 static std::string
emailmap_replace(const char *str
,
1433 const std::string
&user_value
,
1434 const std::string
&realm_value
)
1436 std::ostringstream o
;
1442 while (*str
&& *str
!= '@')
1445 o
<< std::string(p
, str
);
1453 while (*str
&& *str
!= '@')
1456 std::string
key(p
, str
);
1463 else if (key
== "realm")
1470 static int auth_ldap_try(const char *service
,
1471 const char *unquoted_user
, const char *pass
,
1472 int (*callback
)(struct authinfo
*, void *),
1473 void *arg
, const char *newpass
)
1478 char *q
=courier_auth_ldap_escape(unquoted_user
);
1484 if (ldapopen()) return (-1);
1486 std::string::iterator at
=std::find(user
.begin(), user
.end(), '@');
1488 std::string emailmap
;
1490 authldaprc
.config("LDAP_EMAILMAP", emailmap
, false);
1494 if (!authldaprc
.config("LDAP_MAIL", mail
, false, "mail"))
1497 if (emailmap
.empty() || at
== user
.end())
1499 authldap_lookup
real_lookup(service
, mail
, user
, pass
,
1500 newpass
, user
.c_str());
1502 return real_lookup(callback
, arg
);
1505 std::string
user_value(user
.begin(), at
);
1506 std::string
realm_value(++at
, user
.end());
1509 emailmap_replace(emailmap
.c_str(), user_value
, realm_value
);
1511 DPRINTF("using emailmap search: %s", query
.c_str());
1515 tv
.tv_sec
=authldaprc
.timeout
;
1518 std::vector
<std::string
> attributes
;
1520 attributes
.push_back("");
1522 authldaprc
.config("LDAP_EMAILMAP_ATTRIBUTE", attributes
[0], false);
1524 if (attributes
[0].empty())
1525 attributes
[0]="handle";
1529 if (!authldaprc
.config("LDAP_EMAILMAP_BASEDN", basedn
, true))
1532 authldaprc_search_result
1533 lookup(main_connection
,
1541 if (main_connection
.connection
) return (-1);
1545 int cnt
=ldap_count_entries(main_connection
.connection
, lookup
.ptr
);
1549 courier_auth_err("emailmap: %d entries returned from search %s (but we need exactly 1)",
1550 cnt
, query
.c_str());
1554 LDAPMessage
*entry
=ldap_first_entry(main_connection
.connection
, lookup
.ptr
);
1558 courier_auth_err("authldap: unexpected NULL from ldap_first_entry");
1562 authldap_get_values
get_value(main_connection
.connection
, entry
, query
);
1566 get_value(attributes
[0], v
);
1570 DPRINTF("emailmap: empty attribute");
1575 std::string attrname
;
1577 authldaprc
.config("LDAP_EMAILMAP_MAIL", attrname
, false);
1579 if (attrname
.empty())
1584 DPRINTF("emailmap: attribute=%s, value=%s", attrname
.c_str(),
1587 authldap_lookup
real_lookup(service
, attrname
, v
.c_str(), pass
,
1588 newpass
, user
.c_str());
1590 return real_lookup(callback
, arg
);
1593 // Try the query once. If there's a connection-level error, try again.
1595 static int auth_ldap_retry(const char *service
,
1596 const char *unquoted_user
,
1598 int (*callback
)(struct authinfo
*, void *),
1599 void *arg
, const char *newpass
)
1601 int rc
=auth_ldap_try(service
, unquoted_user
, pass
, callback
, arg
,
1605 rc
=auth_ldap_try(service
, unquoted_user
, pass
, callback
, arg
,
1617 int auth_ldap_changepw(const char *dummy
, const char *user
,
1619 const char *newpass
)
1621 if (!authldaprc
.load())
1624 return auth_ldap_retry("authlib", user
, pass
, NULL
, NULL
, newpass
);
1627 int authldapcommon(const char *service
,
1628 const char *user
, const char *pass
,
1629 int (*callback
)(struct authinfo
*, void *),
1632 if (!authldaprc
.load())
1634 return (auth_ldap_retry(service
, user
, pass
, callback
, arg
, NULL
));
1637 void authldapclose()
1639 cpp_authldapclose();
1642 void auth_ldap_enumerate( void(*cb_func
)(const char *name
,
1645 const char *homedir
,
1646 const char *maildir
,
1647 const char *options
,
1651 if (!authldaprc
.load())
1654 cpp_auth_ldap_enumerate(cb_func
, void_arg
);