2
Copyright 2005 Red Hat, Inc.
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions are met:
9
* Redistributions of source code must retain the above copyright
10
notice, this list of conditions and the following disclaimer.
11
* Redistributions in binary form must reproduce the above copyright
12
notice, this list of conditions and the following disclaimer in
13
the documentation and/or other materials provided with the
15
* Neither the name of Red Hat, Inc., nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
* This file implements SASL authentication to an LDAP server for the
37
* following mechanisms:
38
* GSSAPI, EXTERNAL, ANONYMOUS, PLAIN, DIGEST-MD5, KERBEROS_V5, LOGIN
39
* The mechanism to use is specified in an external file,
40
* LDAP_AUTH_CONF_FILE. See the samples directory in the autofs
41
* distribution for an example configuration file.
43
* This file is written with the intent that it will work with both the
44
* openldap and the netscape ldap client libraries.
46
* Author: Nalin Dahyabhai <nalin@redhat.com>
47
* Modified by Jeff Moyer <jmoyer@redhat.com> to adapt it to autofs.
49
#include <sys/types.h>
55
#include <sasl/sasl.h>
57
#include "automount.h"
58
#include "lookup_ldap.h"
60
#ifndef LDAP_OPT_RESULT_CODE
61
#ifdef LDAP_OPT_ERROR_NUMBER
62
#define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER
64
#error "Could not determine the proper value for LDAP_OPT_RESULT_CODE."
69
* Once a krb5 credentials cache is setup, we need to set the KRB5CCNAME
70
* environment variable so that the library knows where to find it.
72
static const char *krb5ccenv = "KRB5CCNAME";
73
static const char *krb5ccval = "MEMORY:_autofstkt";
74
static const char *default_client = "autofsclient";
75
static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
76
static unsigned int krb5cc_in_use = 0;
78
static int sasl_log_func(void *, int, const char *);
79
static int getpass_func(sasl_conn_t *, void *, int, sasl_secret_t **);
80
static int getuser_func(void *, int, const char **, unsigned *);
82
static sasl_callback_t callbacks[] = {
83
{ SASL_CB_LOG, &sasl_log_func, NULL },
84
{ SASL_CB_USER, &getuser_func, NULL },
85
{ SASL_CB_AUTHNAME, &getuser_func, NULL },
86
{ SASL_CB_PASS, &getpass_func, NULL },
87
{ SASL_CB_LIST_END, NULL, NULL },
90
static char *sasl_auth_id = NULL;
91
static char *sasl_auth_secret = NULL;
94
sasl_log_func(void *context, int level, const char *message)
99
logerr("%s", message);
102
logmsg("%s", message);
105
logmsg("%s", message);
110
debug(LOGOPT_DEBUG, "%s", message);
120
getuser_func(void *context, int id, const char **result, unsigned *len)
122
debug(LOGOPT_NONE, "called with context %p, id %d.", context, id);
126
case SASL_CB_AUTHNAME:
127
*result = sasl_auth_id;
129
*len = strlen(sasl_auth_id);
132
error(LOGOPT_VERBOSE, "unknown id in request: %d", id);
140
* This function creates a sasl_secret_t from the credentials specified in
141
* the configuration file. sasl_client_auth can return SASL_OK or
142
* SASL_NOMEM. We simply propagate this return value to the caller.
145
getpass_func(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
147
int len = strlen(sasl_auth_secret);
149
debug(LOGOPT_NONE, "context %p, id %d", context, id);
151
*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
155
(*psecret)->len = strlen(sasl_auth_secret);
156
strncpy((char *)(*psecret)->data, sasl_auth_secret, len);
162
* retrieves the supportedSASLmechanisms from the LDAP server.
164
* Return Value: the result of ldap_get_values on success, NULL on failure.
165
* The caller is responsible for calling ldap_value_free on
169
get_server_SASL_mechanisms(unsigned logopt, LDAP *ld)
172
const char *saslattrlist[] = {"supportedSASLmechanisms", NULL};
173
LDAPMessage *results = NULL, *entry;
176
ret = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
177
(char **)saslattrlist, 0,
179
NULL, LDAP_NO_LIMIT, &results);
180
if (ret != LDAP_SUCCESS) {
181
error(logopt, "%s", ldap_err2string(ret));
185
entry = ldap_first_entry(ld, results);
187
/* No root DSE. (!) */
188
ldap_msgfree(results);
190
"a lookup of \"supportedSASLmechanisms\" returned "
195
mechanisms = ldap_get_values(ld, entry, "supportedSASLmechanisms");
196
ldap_msgfree(results);
197
if (mechanisms == NULL) {
198
/* Well, that was a waste of time. */
199
info(logopt, "No SASL authentication mechanisms are supported"
200
" by the LDAP server.");
208
* Returns 0 upon successful connect, -1 on failure.
211
do_sasl_bind(unsigned logopt, LDAP *ld, sasl_conn_t *conn, const char **clientout,
212
unsigned int *clientoutlen, const char *auth_mech, int sasl_result)
214
int ret, msgid, bind_result;
215
struct berval client_cred, *server_cred, temp_cred;
216
LDAPMessage *results;
217
int have_data, expected_data;
220
/* Take whatever client data we have and send it to the
222
client_cred.bv_val = (char *)*clientout;
223
client_cred.bv_len = *clientoutlen;
224
ret = ldap_sasl_bind(ld, NULL, auth_mech,
225
(client_cred.bv_len > 0) ?
228
if (ret != LDAP_SUCCESS) {
230
"Error sending sasl_bind request to "
231
"the server: %s", ldap_err2string(ret));
235
/* Wait for a result message for this bind request. */
237
ret = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &results);
238
if (ret != LDAP_RES_BIND) {
240
"Error while waiting for response to "
241
"sasl_bind request: %s", ldap_err2string(ret));
245
/* Retrieve the result code for the bind request and
246
* any data which the server sent. */
248
ret = ldap_parse_sasl_bind_result(ld, results,
250
ldap_msgfree(results);
252
/* Okay, here's where things get tricky. Both
253
* Mozilla's LDAP SDK and OpenLDAP store the result
254
* code which was returned by the server in the
255
* handle's ERROR_NUMBER option. Mozilla returns
256
* LDAP_SUCCESS if the data was parsed correctly, even
257
* if the result was an error, while OpenLDAP returns
258
* the result code. I'm leaning toward Mozilla being
260
* In either case, we stuff the result into bind_result.
262
if (ret == LDAP_SUCCESS) {
264
ret = ldap_get_option(ld, LDAP_OPT_RESULT_CODE,
266
if (ret != LDAP_SUCCESS) {
268
"Error retrieving response to sasl_bind "
269
"request: %s", ldap_err2string(ret));
276
case LDAP_SASL_BIND_IN_PROGRESS:
281
"Error parsing response to sasl_bind "
282
"request: %s.", ldap_err2string(ret));
288
* The LDAP server is supposed to send a NULL value for
289
* server_cred if there was no data. However, *some*
290
* server implementations get this wrong, and instead send
291
* an empty string. We check for both.
293
have_data = server_cred != NULL && server_cred->bv_len > 0;
296
* If the result of the sasl_client_start is SASL_CONTINUE,
297
* then the server should have sent us more data.
299
expected_data = sasl_result == SASL_CONTINUE;
301
if (have_data && !expected_data) {
303
"The LDAP server sent data in response to our "
304
"bind request, but indicated that the bind was "
305
"complete. LDAP SASL bind with mechansim %s "
306
"failed.", auth_mech);
310
if (expected_data && !have_data) {
312
"The LDAP server indicated that the LDAP SASL "
313
"bind was incomplete, but did not provide the "
314
"required data to proceed. LDAP SASL bind with "
315
"mechanism %s failed.", auth_mech);
320
/* If we need another round trip, process whatever we
321
* received and prepare data to be transmitted back. */
322
if ((sasl_result == SASL_CONTINUE) &&
323
((bind_result == LDAP_SUCCESS) ||
324
(bind_result == LDAP_SASL_BIND_IN_PROGRESS))) {
325
if (server_cred != NULL) {
326
temp_cred = *server_cred;
328
temp_cred.bv_len = 0;
329
temp_cred.bv_val = NULL;
331
sasl_result = sasl_client_step(conn,
337
/* If we have data to send, then the server
338
* had better be expecting it. (It's valid
339
* to send the server no data with a request.)
341
if ((*clientoutlen > 0) &&
342
(bind_result != LDAP_SASL_BIND_IN_PROGRESS)) {
344
"We have data for the server, "
345
"but it thinks we are done!");
346
/* XXX should print out debug data here */
351
if (server_cred && server_cred->bv_len > 0) {
352
ber_bvfree(server_cred);
356
} while ((bind_result == LDAP_SASL_BIND_IN_PROGRESS) ||
357
(sasl_result == SASL_CONTINUE));
359
if (server_cred && server_cred->bv_len > 0)
360
ber_bvfree(server_cred);
366
* Read client credentials from the default keytab, create a credentials
367
* cache, add the TGT to that cache, and set the environment variable so
368
* that the sasl/krb5 libraries can find our credentials.
370
* Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
371
* are set for cleanup purposes. The krb5 context and ccache entries in
372
* the lookup_context are also filled in.
374
* Upon failure, -1 is returned.
377
sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
380
krb5_principal tgs_princ, krb5_client_princ;
385
if (ctxt->kinit_done)
387
ctxt->kinit_done = 1;
390
"initializing kerberos ticket: client principal %s",
391
ctxt->client_princ ? ctxt->client_princ : default_client);
393
ret = krb5_init_context(&ctxt->krb5ctxt);
395
error(logopt, "krb5_init_context failed with %d", ret);
399
ret = krb5_cc_resolve(ctxt->krb5ctxt, krb5ccval, &ctxt->krb5_ccache);
401
error(logopt, "krb5_cc_resolve failed with error %d",
403
krb5_free_context(ctxt->krb5ctxt);
407
if (ctxt->client_princ) {
409
"calling krb5_parse_name on client principal %s",
412
ret = krb5_parse_name(ctxt->krb5ctxt, ctxt->client_princ,
416
"krb5_parse_name failed for "
417
"specified client principal %s",
422
char *tmp_name = NULL;
425
"calling krb5_sname_to_principal using defaults");
427
ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
428
default_client, KRB5_NT_SRV_HST,
432
"krb5_sname_to_principal failed for "
433
"%s with error %d", default_client, ret);
438
ret = krb5_unparse_name(ctxt->krb5ctxt,
439
krb5_client_princ, &tmp_name);
442
"krb5_unparse_name failed with error %d",
444
goto out_cleanup_client_princ;
448
"principal used for authentication: %s", tmp_name);
450
krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
453
/* setup a principal for the ticket granting service */
454
ret = krb5_build_principal_ext(ctxt->krb5ctxt, &tgs_princ,
455
krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->length,
456
krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->data,
457
strlen(KRB5_TGS_NAME), KRB5_TGS_NAME,
458
krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->length,
459
krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->data,
463
"krb5_build_principal failed with error %d", ret);
464
goto out_cleanup_client_princ;
467
ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
469
error(logopt, "krb5_unparse_name failed with error %d",
471
goto out_cleanup_client_princ;
474
debug(logopt, "Using tgs name %s", tgs_name);
476
memset(&my_creds, 0, sizeof(my_creds));
477
ret = krb5_get_init_creds_keytab(ctxt->krb5ctxt, &my_creds,
480
0 /* relative start time */,
484
"krb5_get_init_creds_keytab failed with error %d",
486
goto out_cleanup_unparse;
489
status = pthread_mutex_lock(&krb5cc_mutex);
493
if (krb5cc_in_use++ == 0)
494
/* tell the cache what the default principal is */
495
ret = krb5_cc_initialize(ctxt->krb5ctxt,
496
ctxt->krb5_ccache, krb5_client_princ);
498
status = pthread_mutex_unlock(&krb5cc_mutex);
504
"krb5_cc_initialize failed with error %d", ret);
505
goto out_cleanup_creds;
508
/* and store credentials for that principal */
509
ret = krb5_cc_store_cred(ctxt->krb5ctxt, ctxt->krb5_ccache, &my_creds);
512
"krb5_cc_store_cred failed with error %d", ret);
513
goto out_cleanup_creds;
516
/* finally, set the environment variable to point to our
517
* credentials cache */
518
if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
519
error(logopt, "setenv failed with %d", errno);
520
goto out_cleanup_creds;
522
ctxt->kinit_successful = 1;
524
debug(logopt, "Kerberos authentication was successful!");
526
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
527
krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
528
krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
529
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
535
krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
537
krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
538
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
539
out_cleanup_client_princ:
540
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
542
status = pthread_mutex_lock(&krb5cc_mutex);
547
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
549
ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
552
"krb5_cc_destroy failed with non-fatal error %d", ret);
554
status = pthread_mutex_unlock(&krb5cc_mutex);
558
krb5_free_context(ctxt->krb5ctxt);
564
* Check a client given external credential cache.
566
* Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
567
* are set for cleanup purposes. The krb5 context and ccache entries in
568
* the lookup_context are also filled in.
570
* Upon failure, -1 is returned.
573
sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt)
575
krb5_principal def_princ;
576
krb5_principal krb5_client_princ;
578
char *cc_princ, *client_princ;
580
if (ctxt->kinit_done)
582
ctxt->kinit_done = 1;
585
"using external credential cache for auth: client principal %s",
586
ctxt->client_princ ? ctxt->client_princ : default_client);
588
ret = krb5_init_context(&ctxt->krb5ctxt);
590
error(logopt, "krb5_init_context failed with %d", ret);
594
ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
596
error(logopt, "krb5_cc_resolve failed with error %d",
598
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
599
krb5_free_context(ctxt->krb5ctxt);
603
ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
605
error(logopt, "krb5_cc_get_principal failed with error %d", ret);
606
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
607
krb5_free_context(ctxt->krb5ctxt);
611
ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
613
error(logopt, "krb5_unparse_name failed with error %d", ret);
614
krb5_free_principal(ctxt->krb5ctxt, def_princ);
615
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
616
krb5_free_context(ctxt->krb5ctxt);
620
debug(logopt, "external credential cache default principal %s", cc_princ);
623
* If the principal isn't set in the config construct the default
624
* so we can check against the default principal of the external
627
if (ctxt->client_princ)
628
client_princ = ctxt->client_princ;
631
"calling krb5_sname_to_principal using defaults");
633
ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
634
default_client, KRB5_NT_SRV_HST,
638
"krb5_sname_to_principal failed for "
639
"%s with error %d", default_client, ret);
640
krb5_free_principal(ctxt->krb5ctxt, def_princ);
641
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
642
krb5_free_context(ctxt->krb5ctxt);
647
ret = krb5_unparse_name(ctxt->krb5ctxt,
648
krb5_client_princ, &client_princ);
651
"krb5_unparse_name failed with error %d",
653
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
654
krb5_free_principal(ctxt->krb5ctxt, def_princ);
655
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
656
krb5_free_context(ctxt->krb5ctxt);
661
"principal used for authentication: %s", client_princ);
663
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
667
* Check if the principal to be used matches the default principal in
668
* the external cred cache.
670
if (strcmp(cc_princ, client_princ)) {
672
"configured client principal %s ",
675
"external credential cache default principal %s",
678
"cannot use credential cache, external "
679
"default principal does not match configured "
681
if (!ctxt->client_princ)
682
krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
683
krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
684
krb5_free_principal(ctxt->krb5ctxt, def_princ);
685
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
686
krb5_free_context(ctxt->krb5ctxt);
690
if (!ctxt->client_princ)
691
krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
692
krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
693
krb5_free_principal(ctxt->krb5ctxt, def_princ);
695
/* Set the environment variable to point to the external cred cache */
696
if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) {
697
error(logopt, "setenv failed with %d", errno);
698
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
699
krb5_free_context(ctxt->krb5ctxt);
702
ctxt->kinit_successful = 1;
704
debug(logopt, "Kerberos authentication was successful!");
710
* Attempt to bind to the ldap server using a given authentication
711
* mechanism. ldap should be a properly initialzed ldap pointer.
713
* Returns a valid sasl_conn_t pointer upon success, NULL on failure.
716
sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *mech)
719
char *tmp, *host = NULL;
720
const char *clientout;
721
unsigned int clientoutlen;
722
const char *chosen_mech;
725
if (!strncmp(mech, "GSSAPI", 6)) {
727
result = sasl_do_kinit_ext_cc(logopt, ctxt);
729
result = sasl_do_kinit(logopt, ctxt);
734
debug(logopt, "Attempting sasl bind with mechanism %s", mech);
736
result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
737
if (result != LDAP_OPT_SUCCESS || !host) {
738
debug(logopt, "failed to get hostname for connection");
742
if ((tmp = strrchr(host, ':'))) {
743
if (*(tmp - 1) != ']') {
754
/* Create a new authentication context for the service. */
755
result = sasl_client_new("ldap", tmp, NULL, NULL, NULL, 0, &conn);
756
if (result != SASL_OK) {
757
error(logopt, "sasl_client_new failed with error %d",
764
result = sasl_client_start(conn, mech, NULL,
765
&clientout, &clientoutlen, &chosen_mech);
767
/* OK and CONTINUE are the only non-fatal return codes here. */
768
if ((result != SASL_OK) && (result != SASL_CONTINUE)) {
769
warn(logopt, "sasl_client_start failed for %s", host);
770
debug(logopt, "sasl_client_start: %s", sasl_errdetail(conn));
776
result = do_sasl_bind(logopt, ldap, conn,
777
&clientout, &clientoutlen, chosen_mech, result);
780
debug(logopt, "sasl bind with mechanism %s succeeded",
785
info(logopt, "sasl bind with mechanism %s failed", mech);
787
/* sasl bind failed */
795
* Returns 0 if a suitable authentication mechanism is available. Returns
796
* -1 on error or if no mechanism is supported by both client and server.
799
sasl_choose_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
801
sasl_conn_t *conn = NULL;
806
mechanisms = get_server_SASL_mechanisms(logopt, ldap);
810
/* Try each supported mechanism in turn. */
812
for (i = 0; mechanisms[i] != NULL; i++) {
814
* This routine is called if there is no configured
815
* mechanism. As such, we can skip over any auth
816
* mechanisms that require user credentials. These include
817
* PLAIN, LOGIN, and DIGEST-MD5.
819
if (authtype_requires_creds(mechanisms[i]))
822
conn = sasl_bind_mech(logopt, ldap, ctxt, mechanisms[i]);
824
ctxt->sasl_mech = strdup(mechanisms[i]);
825
if (!ctxt->sasl_mech) {
826
crit(logopt, "Successfully authenticated with "
827
"mechanism %s, but failed to allocate "
828
"memory to hold the mechanism type.",
831
ldap_value_free(mechanisms);
837
debug(logopt, "Failed to authenticate with mech %s",
841
debug(logopt, "authenticated: %d, sasl_mech: %s",
842
authenticated, ctxt->sasl_mech);
844
ldap_value_free(mechanisms);
849
* Routine called when unbinding an ldap connection.
852
autofs_sasl_unbind(struct lookup_context *ctxt)
854
if (ctxt->sasl_conn) {
855
sasl_dispose(&ctxt->sasl_conn);
856
ctxt->sasl_conn = NULL;
861
* Given a lookup context that has been initialized with any user-specified
862
* parameters, figure out which sasl mechanism to use. Then, initialize
863
* the necessary parameters to authenticate with the chosen mechanism.
870
autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
872
sasl_conn_t *conn = NULL;
874
/* If we already have a connection use it */
878
if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
882
"Attempting sasl bind with mechanism %s",
885
result = do_sasl_extern(ldap, ctxt);
888
"Failed to authenticate with mech %s",
892
"sasl bind with mechanism %s succeeded",
898
sasl_auth_id = ctxt->user;
899
sasl_auth_secret = ctxt->secret;
901
if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) {
902
if (ctxt->sasl_mech) {
903
free(ctxt->sasl_mech);
904
ctxt->sasl_mech = NULL;
909
* If LDAP_AUTH_AUTODETECT is set, it means that there was no
910
* mechanism specified in the configuration file or auto
911
* selection has been requested, so try to auto-select an
915
conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech);
917
conn = sasl_choose_mech(logopt, ldap, ctxt);
922
ctxt->sasl_conn = conn;
927
* Destructor routine. This should be called when finished with an ldap
930
void autofs_sasl_dispose(struct lookup_context *ctxt)
934
if (ctxt->sasl_conn) {
935
sasl_dispose(&ctxt->sasl_conn);
936
ctxt->sasl_conn = NULL;
939
if (ctxt->kinit_successful) {
940
status = pthread_mutex_lock(&krb5cc_mutex);
944
if (--krb5cc_in_use || ctxt->client_cc)
945
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
947
ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
949
logmsg("krb5_cc_destroy failed with non-fatal error %d",
952
status = pthread_mutex_unlock(&krb5cc_mutex);
956
krb5_free_context(ctxt->krb5ctxt);
957
if (unsetenv(krb5ccenv) != 0)
958
logerr("unsetenv failed with error %d", errno);
960
ctxt->krb5ctxt = NULL;
961
ctxt->krb5_ccache = NULL;
962
ctxt->kinit_done = 0;
963
ctxt->kinit_successful = 0;
967
static void *sasl_mutex_new(void)
969
pthread_mutex_t* mutex;
971
mutex = malloc(sizeof(pthread_mutex_t));
975
pthread_mutex_init(mutex, NULL);
977
return (void *) mutex;
980
static int sasl_mutex_lock(void *mutex __attribute__((unused)))
987
rc = pthread_mutex_lock((pthread_mutex_t *) mutex);
989
return (rc==0 ? SASL_OK : SASL_FAIL);
992
static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
999
rc = pthread_mutex_unlock((pthread_mutex_t *) mutex);
1001
return (rc==0 ? SASL_OK : SASL_FAIL);
1004
static void sasl_mutex_dispose(void *mutex __attribute__((unused)))
1011
rc = pthread_mutex_destroy((pthread_mutex_t *) mutex);
1019
* Initialize the sasl callbacks, which increments the global
1022
int autofs_sasl_client_init(unsigned logopt)
1025
sasl_set_mutex(sasl_mutex_new,
1028
sasl_mutex_dispose);
1030
/* Start up Cyrus SASL--only needs to be done at library load. */
1031
if (sasl_client_init(callbacks) != SASL_OK) {
1032
error(logopt, "sasl_client_init failed");
1039
* Decrement the library reference count and free resources if
1040
* we are the last to close the library.
1042
void autofs_sasl_done(void)