|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
Copyright 2005 Red Hat, Inc.
|
|
Packit Service |
a4b2a9 |
All rights reserved.
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
a4b2a9 |
modification, are permitted provided that the following conditions are met:
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
* Redistributions of source code must retain the above copyright
|
|
Packit Service |
a4b2a9 |
notice, this list of conditions and the following disclaimer.
|
|
Packit Service |
a4b2a9 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit Service |
a4b2a9 |
notice, this list of conditions and the following disclaimer in
|
|
Packit Service |
a4b2a9 |
the documentation and/or other materials provided with the
|
|
Packit Service |
a4b2a9 |
distribution.
|
|
Packit Service |
a4b2a9 |
* Neither the name of Red Hat, Inc., nor the names of its
|
|
Packit Service |
a4b2a9 |
contributors may be used to endorse or promote products derived
|
|
Packit Service |
a4b2a9 |
from this software without specific prior written permission.
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
Packit Service |
a4b2a9 |
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
Packit Service |
a4b2a9 |
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit Service |
a4b2a9 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
Packit Service |
a4b2a9 |
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit Service |
a4b2a9 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit Service |
a4b2a9 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit Service |
a4b2a9 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit Service |
a4b2a9 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit Service |
a4b2a9 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit Service |
a4b2a9 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* cyrus-sasl.c
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Description:
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* This file implements SASL authentication to an LDAP server for the
|
|
Packit Service |
a4b2a9 |
* following mechanisms:
|
|
Packit Service |
a4b2a9 |
* GSSAPI, EXTERNAL, ANONYMOUS, PLAIN, DIGEST-MD5, KERBEROS_V5, LOGIN
|
|
Packit Service |
a4b2a9 |
* The mechanism to use is specified in an external file,
|
|
Packit Service |
a4b2a9 |
* LDAP_AUTH_CONF_FILE. See the samples directory in the autofs
|
|
Packit Service |
a4b2a9 |
* distribution for an example configuration file.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* This file is written with the intent that it will work with both the
|
|
Packit Service |
a4b2a9 |
* openldap and the netscape ldap client libraries.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Author: Nalin Dahyabhai <nalin@redhat.com>
|
|
Packit Service |
a4b2a9 |
* Modified by Jeff Moyer <jmoyer@redhat.com> to adapt it to autofs.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
#include <sys/types.h>
|
|
Packit Service |
a4b2a9 |
#include <sys/wait.h>
|
|
Packit Service |
a4b2a9 |
#include <stdio.h>
|
|
Packit Service |
a4b2a9 |
#include <stdlib.h>
|
|
Packit Service |
a4b2a9 |
#include <string.h>
|
|
Packit Service |
a4b2a9 |
#include <sasl/sasl.h>
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
#include "automount.h"
|
|
Packit Service |
a4b2a9 |
#include "lookup_ldap.h"
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
#ifndef LDAP_OPT_RESULT_CODE
|
|
Packit Service |
a4b2a9 |
#ifdef LDAP_OPT_ERROR_NUMBER
|
|
Packit Service |
a4b2a9 |
#define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER
|
|
Packit Service |
a4b2a9 |
#else
|
|
Packit Service |
a4b2a9 |
#error "Could not determine the proper value for LDAP_OPT_RESULT_CODE."
|
|
Packit Service |
a4b2a9 |
#endif
|
|
Packit Service |
a4b2a9 |
#endif
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
#ifdef HAVE_KRB5_PRINCIPAL_GET_REALM
|
|
Packit Service |
a4b2a9 |
void _krb5_princ_realm(krb5_context context, krb5_const_principal princ,
|
|
Packit Service |
a4b2a9 |
const char **realm, int *len)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
*realm = krb5_principal_get_realm(context, princ);
|
|
Packit Service |
a4b2a9 |
if (*realm)
|
|
Packit Service |
a4b2a9 |
*len = strlen(*realm);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
*len = 0;
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
#else
|
|
Packit Service |
a4b2a9 |
void _krb5_princ_realm(krb5_context context, krb5_const_principal princ,
|
|
Packit Service |
a4b2a9 |
const char **realm, int *len)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
const krb5_data *data;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
data = krb5_princ_realm(context, princ);
|
|
Packit Service |
a4b2a9 |
if (data) {
|
|
Packit Service |
a4b2a9 |
*realm = data->data;
|
|
Packit Service |
a4b2a9 |
*len = data->length;
|
|
Packit Service |
a4b2a9 |
} else {
|
|
Packit Service |
a4b2a9 |
*realm = NULL;
|
|
Packit Service |
a4b2a9 |
*len = 0;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
#endif
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Once a krb5 credentials cache is setup, we need to set the KRB5CCNAME
|
|
Packit Service |
a4b2a9 |
* environment variable so that the library knows where to find it.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
static const char *krb5ccenv = "KRB5CCNAME";
|
|
Packit Service |
a4b2a9 |
static const char *krb5ccval = "MEMORY:_autofstkt";
|
|
Packit Service |
a4b2a9 |
static const char *default_client = "autofsclient";
|
|
Packit Service |
a4b2a9 |
static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit Service |
a4b2a9 |
static unsigned int krb5cc_in_use = 0;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static int sasl_log_func(void *, int, const char *);
|
|
Packit Service |
a4b2a9 |
static int getpass_func(sasl_conn_t *, void *, int, sasl_secret_t **);
|
|
Packit Service |
a4b2a9 |
static int getuser_func(void *, int, const char **, unsigned *);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static sasl_callback_t callbacks[] = {
|
|
Packit Service |
a4b2a9 |
{ SASL_CB_LOG, &sasl_log_func, NULL },
|
|
Packit Service |
a4b2a9 |
{ SASL_CB_USER, &getuser_func, NULL },
|
|
Packit Service |
a4b2a9 |
{ SASL_CB_AUTHNAME, &getuser_func, NULL },
|
|
Packit Service |
a4b2a9 |
{ SASL_CB_PASS, &getpass_func, NULL },
|
|
Packit Service |
a4b2a9 |
{ SASL_CB_LIST_END, NULL, NULL },
|
|
Packit Service |
a4b2a9 |
};
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static char *sasl_auth_id = NULL;
|
|
Packit Service |
a4b2a9 |
static char *sasl_auth_secret = NULL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static int
|
|
Packit Service |
a4b2a9 |
sasl_log_func(void *context, int level, const char *message)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
switch (level) {
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_ERR:
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_FAIL:
|
|
Packit Service |
a4b2a9 |
logerr("%s", message);
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_WARN:
|
|
Packit Service |
a4b2a9 |
logmsg("%s", message);
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_NOTE:
|
|
Packit Service |
a4b2a9 |
logmsg("%s", message);
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_DEBUG:
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_TRACE:
|
|
Packit Service |
a4b2a9 |
case SASL_LOG_PASS:
|
|
Packit Service |
a4b2a9 |
debug(LOGOPT_DEBUG, "%s", message);
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
default:
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return SASL_OK;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static int
|
|
Packit Service |
a4b2a9 |
getuser_func(void *context, int id, const char **result, unsigned *len)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
debug(LOGOPT_NONE, "called with context %p, id %d.", context, id);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
switch (id) {
|
|
Packit Service |
a4b2a9 |
case SASL_CB_USER:
|
|
Packit Service |
a4b2a9 |
case SASL_CB_AUTHNAME:
|
|
Packit Service |
a4b2a9 |
*result = sasl_auth_id;
|
|
Packit Service |
a4b2a9 |
if (len)
|
|
Packit Service |
a4b2a9 |
*len = strlen(sasl_auth_id);
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
default:
|
|
Packit Service |
a4b2a9 |
error(LOGOPT_VERBOSE, "unknown id in request: %d", id);
|
|
Packit Service |
a4b2a9 |
return SASL_FAIL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return SASL_OK;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* This function creates a sasl_secret_t from the credentials specified in
|
|
Packit Service |
a4b2a9 |
* the configuration file. sasl_client_auth can return SASL_OK or
|
|
Packit Service |
a4b2a9 |
* SASL_NOMEM. We simply propagate this return value to the caller.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
static int
|
|
Packit Service |
a4b2a9 |
getpass_func(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int len = strlen(sasl_auth_secret);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(LOGOPT_NONE, "context %p, id %d", context, id);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
|
|
Packit Service |
a4b2a9 |
if (!*psecret)
|
|
Packit Service |
a4b2a9 |
return SASL_NOMEM;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
(*psecret)->len = strlen(sasl_auth_secret);
|
|
Packit Service |
a4b2a9 |
strncpy((char *)(*psecret)->data, sasl_auth_secret, len);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return SASL_OK;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* retrieves the supportedSASLmechanisms from the LDAP server.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Return Value: the result of ldap_get_values on success, NULL on failure.
|
|
Packit Service |
a4b2a9 |
* The caller is responsible for calling ldap_value_free on
|
|
Packit Service |
a4b2a9 |
* the returned data.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
char **
|
|
Packit Service |
a4b2a9 |
get_server_SASL_mechanisms(unsigned logopt, LDAP *ld)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int ret;
|
|
Packit Service |
a4b2a9 |
const char *saslattrlist[] = {"supportedSASLmechanisms", NULL};
|
|
Packit Service |
a4b2a9 |
LDAPMessage *results = NULL, *entry;
|
|
Packit Service |
a4b2a9 |
char **mechanisms;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
|
|
Packit Service |
a4b2a9 |
(char **)saslattrlist, 0,
|
|
Packit Service |
a4b2a9 |
NULL, NULL,
|
|
Packit Service |
a4b2a9 |
NULL, LDAP_NO_LIMIT, &results);
|
|
Packit Service |
a4b2a9 |
if (ret != LDAP_SUCCESS) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "%s", ldap_err2string(ret));
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
entry = ldap_first_entry(ld, results);
|
|
Packit Service |
a4b2a9 |
if (entry == NULL) {
|
|
Packit Service |
a4b2a9 |
/* No root DSE. (!) */
|
|
Packit Service |
a4b2a9 |
ldap_msgfree(results);
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"a lookup of \"supportedSASLmechanisms\" returned "
|
|
Packit Service |
a4b2a9 |
"no results.");
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
mechanisms = ldap_get_values(ld, entry, "supportedSASLmechanisms");
|
|
Packit Service |
a4b2a9 |
ldap_msgfree(results);
|
|
Packit Service |
a4b2a9 |
if (mechanisms == NULL) {
|
|
Packit Service |
a4b2a9 |
/* Well, that was a waste of time. */
|
|
Packit Service |
a4b2a9 |
info(logopt, "No SASL authentication mechanisms are supported"
|
|
Packit Service |
a4b2a9 |
" by the LDAP server.");
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return mechanisms;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Returns 0 upon successful connect, -1 on failure.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
int
|
|
Packit Service |
a4b2a9 |
do_sasl_bind(unsigned logopt, LDAP *ld, sasl_conn_t *conn, const char **clientout,
|
|
Packit Service |
a4b2a9 |
unsigned int *clientoutlen, const char *auth_mech, int sasl_result)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int ret, msgid, bind_result = LDAP_OTHER;
|
|
Packit Service |
a4b2a9 |
struct berval client_cred, *server_cred, temp_cred;
|
|
Packit Service |
a4b2a9 |
LDAPMessage *results;
|
|
Packit Service |
a4b2a9 |
int have_data, expected_data;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
do {
|
|
Packit Service |
a4b2a9 |
/* Take whatever client data we have and send it to the
|
|
Packit Service |
a4b2a9 |
* server. */
|
|
Packit Service |
a4b2a9 |
client_cred.bv_val = (char *)*clientout;
|
|
Packit Service |
a4b2a9 |
client_cred.bv_len = *clientoutlen;
|
|
Packit Service |
a4b2a9 |
ret = ldap_sasl_bind(ld, NULL, auth_mech,
|
|
Packit Service |
a4b2a9 |
(client_cred.bv_len > 0) ?
|
|
Packit Service |
a4b2a9 |
&client_cred : NULL,
|
|
Packit Service |
a4b2a9 |
NULL, NULL, &msgid);
|
|
Packit Service |
a4b2a9 |
if (ret != LDAP_SUCCESS) {
|
|
Packit Service |
a4b2a9 |
crit(logopt,
|
|
Packit Service |
a4b2a9 |
"Error sending sasl_bind request to "
|
|
Packit Service |
a4b2a9 |
"the server: %s", ldap_err2string(ret));
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Wait for a result message for this bind request. */
|
|
Packit Service |
a4b2a9 |
results = NULL;
|
|
Packit Service |
a4b2a9 |
ret = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &results);
|
|
Packit Service |
a4b2a9 |
if (ret != LDAP_RES_BIND) {
|
|
Packit Service |
a4b2a9 |
crit(logopt,
|
|
Packit Service |
a4b2a9 |
"Error while waiting for response to "
|
|
Packit Service |
a4b2a9 |
"sasl_bind request: %s", ldap_err2string(ret));
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Retrieve the result code for the bind request and
|
|
Packit Service |
a4b2a9 |
* any data which the server sent. */
|
|
Packit Service |
a4b2a9 |
server_cred = NULL;
|
|
Packit Service |
a4b2a9 |
ret = ldap_parse_sasl_bind_result(ld, results,
|
|
Packit Service |
a4b2a9 |
&server_cred, 0);
|
|
Packit Service |
a4b2a9 |
ldap_msgfree(results);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Okay, here's where things get tricky. Both
|
|
Packit Service |
a4b2a9 |
* Mozilla's LDAP SDK and OpenLDAP store the result
|
|
Packit Service |
a4b2a9 |
* code which was returned by the server in the
|
|
Packit Service |
a4b2a9 |
* handle's ERROR_NUMBER option. Mozilla returns
|
|
Packit Service |
a4b2a9 |
* LDAP_SUCCESS if the data was parsed correctly, even
|
|
Packit Service |
a4b2a9 |
* if the result was an error, while OpenLDAP returns
|
|
Packit Service |
a4b2a9 |
* the result code. I'm leaning toward Mozilla being
|
|
Packit Service |
a4b2a9 |
* more correct.
|
|
Packit Service |
a4b2a9 |
* In either case, we stuff the result into bind_result.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if (ret == LDAP_SUCCESS) {
|
|
Packit Service |
a4b2a9 |
/* Mozilla? */
|
|
Packit Service |
a4b2a9 |
ret = ldap_get_option(ld, LDAP_OPT_RESULT_CODE,
|
|
Packit Service |
a4b2a9 |
&bind_result);
|
|
Packit Service |
a4b2a9 |
if (ret != LDAP_SUCCESS) {
|
|
Packit Service |
a4b2a9 |
crit(logopt,
|
|
Packit Service |
a4b2a9 |
"Error retrieving response to sasl_bind "
|
|
Packit Service |
a4b2a9 |
"request: %s", ldap_err2string(ret));
|
|
Packit Service |
a4b2a9 |
ret = -1;
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
} else {
|
|
Packit Service |
a4b2a9 |
/* OpenLDAP? */
|
|
Packit Service |
a4b2a9 |
switch (ret) {
|
|
Packit Service |
a4b2a9 |
case LDAP_SASL_BIND_IN_PROGRESS:
|
|
Packit Service |
a4b2a9 |
bind_result = ret;
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
default:
|
|
Packit Service |
a4b2a9 |
warn(logopt,
|
|
Packit Service |
a4b2a9 |
"Error parsing response to sasl_bind "
|
|
Packit Service |
a4b2a9 |
"request: %s.", ldap_err2string(ret));
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* The LDAP server is supposed to send a NULL value for
|
|
Packit Service |
a4b2a9 |
* server_cred if there was no data. However, *some*
|
|
Packit Service |
a4b2a9 |
* server implementations get this wrong, and instead send
|
|
Packit Service |
a4b2a9 |
* an empty string. We check for both.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
have_data = server_cred != NULL && server_cred->bv_len > 0;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* If the result of the sasl_client_start is SASL_CONTINUE,
|
|
Packit Service |
a4b2a9 |
* then the server should have sent us more data.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
expected_data = sasl_result == SASL_CONTINUE;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (have_data && !expected_data) {
|
|
Packit Service |
a4b2a9 |
warn(logopt,
|
|
Packit Service |
a4b2a9 |
"The LDAP server sent data in response to our "
|
|
Packit Service |
a4b2a9 |
"bind request, but indicated that the bind was "
|
|
Packit Service |
a4b2a9 |
"complete. LDAP SASL bind with mechansim %s "
|
|
Packit Service |
a4b2a9 |
"failed.", auth_mech);
|
|
Packit Service |
a4b2a9 |
ret = -1;
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
if (expected_data && !have_data) {
|
|
Packit Service |
a4b2a9 |
warn(logopt,
|
|
Packit Service |
a4b2a9 |
"The LDAP server indicated that the LDAP SASL "
|
|
Packit Service |
a4b2a9 |
"bind was incomplete, but did not provide the "
|
|
Packit Service |
a4b2a9 |
"required data to proceed. LDAP SASL bind with "
|
|
Packit Service |
a4b2a9 |
"mechanism %s failed.", auth_mech);
|
|
Packit Service |
a4b2a9 |
ret = -1;
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* If we need another round trip, process whatever we
|
|
Packit Service |
a4b2a9 |
* received and prepare data to be transmitted back. */
|
|
Packit Service |
a4b2a9 |
if ((sasl_result == SASL_CONTINUE) &&
|
|
Packit Service |
a4b2a9 |
((bind_result == LDAP_SUCCESS) ||
|
|
Packit Service |
a4b2a9 |
(bind_result == LDAP_SASL_BIND_IN_PROGRESS))) {
|
|
Packit Service |
a4b2a9 |
if (server_cred != NULL) {
|
|
Packit Service |
a4b2a9 |
temp_cred = *server_cred;
|
|
Packit Service |
a4b2a9 |
} else {
|
|
Packit Service |
a4b2a9 |
temp_cred.bv_len = 0;
|
|
Packit Service |
a4b2a9 |
temp_cred.bv_val = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
sasl_result = sasl_client_step(conn,
|
|
Packit Service |
a4b2a9 |
temp_cred.bv_val,
|
|
Packit Service |
a4b2a9 |
temp_cred.bv_len,
|
|
Packit Service |
a4b2a9 |
NULL,
|
|
Packit Service |
a4b2a9 |
clientout,
|
|
Packit Service |
a4b2a9 |
clientoutlen);
|
|
Packit Service |
a4b2a9 |
/* If we have data to send, then the server
|
|
Packit Service |
a4b2a9 |
* had better be expecting it. (It's valid
|
|
Packit Service |
a4b2a9 |
* to send the server no data with a request.)
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if ((*clientoutlen > 0) &&
|
|
Packit Service |
a4b2a9 |
(bind_result != LDAP_SASL_BIND_IN_PROGRESS)) {
|
|
Packit Service |
a4b2a9 |
warn(logopt,
|
|
Packit Service |
a4b2a9 |
"We have data for the server, "
|
|
Packit Service |
a4b2a9 |
"but it thinks we are done!");
|
|
Packit Service |
a4b2a9 |
/* XXX should print out debug data here */
|
|
Packit Service |
a4b2a9 |
ret = -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (server_cred && server_cred->bv_len > 0) {
|
|
Packit Service |
a4b2a9 |
ber_bvfree(server_cred);
|
|
Packit Service |
a4b2a9 |
server_cred = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
} while ((bind_result == LDAP_SASL_BIND_IN_PROGRESS) ||
|
|
Packit Service |
a4b2a9 |
(sasl_result == SASL_CONTINUE));
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (server_cred && server_cred->bv_len > 0)
|
|
Packit Service |
a4b2a9 |
ber_bvfree(server_cred);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return ret;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Read client credentials from the default keytab, create a credentials
|
|
Packit Service |
a4b2a9 |
* cache, add the TGT to that cache, and set the environment variable so
|
|
Packit Service |
a4b2a9 |
* that the sasl/krb5 libraries can find our credentials.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
|
|
Packit Service |
a4b2a9 |
* are set for cleanup purposes. The krb5 context and ccache entries in
|
|
Packit Service |
a4b2a9 |
* the lookup_context are also filled in.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Upon failure, -1 is returned.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
int
|
|
Packit Service |
a4b2a9 |
sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
krb5_error_code ret;
|
|
Packit Service |
a4b2a9 |
krb5_principal tgs_princ, krb5_client_princ;
|
|
Packit Service |
a4b2a9 |
krb5_creds my_creds;
|
|
Packit Service |
a4b2a9 |
char *tgs_name;
|
|
Packit Service |
a4b2a9 |
const char *realm_name;
|
|
Packit Service |
a4b2a9 |
int status, realm_length;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->kinit_done)
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_done = 1;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"initializing kerberos ticket: client principal %s",
|
|
Packit Service |
a4b2a9 |
ctxt->client_princ ? ctxt->client_princ : default_client);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_init_context(&ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_init_context failed with %d", ret);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_resolve(ctxt->krb5ctxt, krb5ccval, &ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_cc_resolve failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->client_princ) {
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"calling krb5_parse_name on client principal %s",
|
|
Packit Service |
a4b2a9 |
ctxt->client_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_parse_name(ctxt->krb5ctxt, ctxt->client_princ,
|
|
Packit Service |
a4b2a9 |
&krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_parse_name failed for "
|
|
Packit Service |
a4b2a9 |
"specified client principal %s",
|
|
Packit Service |
a4b2a9 |
ctxt->client_princ);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_cc;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
} else {
|
|
Packit Service |
a4b2a9 |
char *tmp_name = NULL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"calling krb5_sname_to_principal using defaults");
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
|
|
Packit Service |
a4b2a9 |
default_client, KRB5_NT_SRV_HST,
|
|
Packit Service |
a4b2a9 |
&krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_sname_to_principal failed for "
|
|
Packit Service |
a4b2a9 |
"%s with error %d", default_client, ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_cc;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_unparse_name(ctxt->krb5ctxt,
|
|
Packit Service |
a4b2a9 |
krb5_client_princ, &tmp_name);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_unparse_name failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_client_princ;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"principal used for authentication: %s", tmp_name);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* setup a principal for the ticket granting service */
|
|
Packit Service |
a4b2a9 |
_krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ, &realm_name, &realm_length);
|
|
Packit Service |
a4b2a9 |
ret = krb5_build_principal_ext(ctxt->krb5ctxt, &tgs_princ,
|
|
Packit Service |
a4b2a9 |
realm_length, realm_name,
|
|
Packit Service |
a4b2a9 |
strlen(KRB5_TGS_NAME), KRB5_TGS_NAME,
|
|
Packit Service |
a4b2a9 |
realm_length, realm_name,
|
|
Packit Service |
a4b2a9 |
0);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_build_principal failed with error %d", ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_client_princ;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_unparse_name failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_client_princ;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "Using tgs name %s", tgs_name);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
memset(&my_creds, 0, sizeof(my_creds));
|
|
Packit Service |
a4b2a9 |
ret = krb5_get_init_creds_keytab(ctxt->krb5ctxt, &my_creds,
|
|
Packit Service |
a4b2a9 |
krb5_client_princ,
|
|
Packit Service |
a4b2a9 |
NULL /*keytab*/,
|
|
Packit Service |
a4b2a9 |
0 /* relative start time */,
|
|
Packit Service |
a4b2a9 |
tgs_name, NULL);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_get_init_creds_keytab failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_unparse;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_lock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (krb5cc_in_use++ == 0)
|
|
Packit Service |
a4b2a9 |
/* tell the cache what the default principal is */
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_initialize(ctxt->krb5ctxt,
|
|
Packit Service |
a4b2a9 |
ctxt->krb5_ccache, krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_unlock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_cc_initialize failed with error %d", ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_creds;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* and store credentials for that principal */
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_store_cred(ctxt->krb5ctxt, ctxt->krb5_ccache, &my_creds);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_cc_store_cred failed with error %d", ret);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_creds;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* finally, set the environment variable to point to our
|
|
Packit Service |
a4b2a9 |
* credentials cache */
|
|
Packit Service |
a4b2a9 |
if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "setenv failed with %d", errno);
|
|
Packit Service |
a4b2a9 |
goto out_cleanup_creds;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_successful = 1;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "Kerberos authentication was successful!");
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
|
|
Packit Service |
a4b2a9 |
krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
out_cleanup_creds:
|
|
Packit Service |
a4b2a9 |
krb5cc_in_use--;
|
|
Packit Service |
a4b2a9 |
krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
|
|
Packit Service |
a4b2a9 |
out_cleanup_unparse:
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
|
|
Packit Service |
a4b2a9 |
out_cleanup_client_princ:
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
out_cleanup_cc:
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_lock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (krb5cc_in_use)
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
if (ret)
|
|
Packit Service |
a4b2a9 |
warn(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_cc_destroy failed with non-fatal error %d", ret);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_unlock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Check a client given external credential cache.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
|
|
Packit Service |
a4b2a9 |
* are set for cleanup purposes. The krb5 context and ccache entries in
|
|
Packit Service |
a4b2a9 |
* the lookup_context are also filled in.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Upon failure, -1 is returned.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
int
|
|
Packit Service |
a4b2a9 |
sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
krb5_principal def_princ;
|
|
Packit Service |
a4b2a9 |
krb5_principal krb5_client_princ;
|
|
Packit Service |
a4b2a9 |
krb5_error_code ret;
|
|
Packit Service |
a4b2a9 |
char *cc_princ, *client_princ;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->kinit_done)
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_done = 1;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"using external credential cache for auth: client principal %s",
|
|
Packit Service |
a4b2a9 |
ctxt->client_princ ? ctxt->client_princ : default_client);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_init_context(&ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_init_context failed with %d", ret);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_cc_resolve failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_cc_get_principal failed with error %d", ret);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "krb5_unparse_name failed with error %d", ret);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, def_princ);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "external credential cache default principal %s", cc_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* If the principal isn't set in the config construct the default
|
|
Packit Service |
a4b2a9 |
* so we can check against the default principal of the external
|
|
Packit Service |
a4b2a9 |
* cred cache.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if (ctxt->client_princ)
|
|
Packit Service |
a4b2a9 |
client_princ = ctxt->client_princ;
|
|
Packit Service |
a4b2a9 |
else {
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"calling krb5_sname_to_principal using defaults");
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
|
|
Packit Service |
a4b2a9 |
default_client, KRB5_NT_SRV_HST,
|
|
Packit Service |
a4b2a9 |
&krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_sname_to_principal failed for "
|
|
Packit Service |
a4b2a9 |
"%s with error %d", default_client, ret);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, def_princ);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ret = krb5_unparse_name(ctxt->krb5ctxt,
|
|
Packit Service |
a4b2a9 |
krb5_client_princ, &client_princ);
|
|
Packit Service |
a4b2a9 |
if (ret) {
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"krb5_unparse_name failed with error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, def_princ);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"principal used for authentication: %s", client_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Check if the principal to be used matches the default principal in
|
|
Packit Service |
a4b2a9 |
* the external cred cache.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if (strcmp(cc_princ, client_princ)) {
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"configured client principal %s ",
|
|
Packit Service |
a4b2a9 |
ctxt->client_princ);
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"external credential cache default principal %s",
|
|
Packit Service |
a4b2a9 |
cc_princ);
|
|
Packit Service |
a4b2a9 |
error(logopt,
|
|
Packit Service |
a4b2a9 |
"cannot use credential cache, external "
|
|
Packit Service |
a4b2a9 |
"default principal does not match configured "
|
|
Packit Service |
a4b2a9 |
"principal");
|
|
Packit Service |
a4b2a9 |
if (!ctxt->client_princ)
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, def_princ);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!ctxt->client_princ)
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
|
|
Packit Service |
a4b2a9 |
krb5_free_principal(ctxt->krb5ctxt, def_princ);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Set the environment variable to point to the external cred cache */
|
|
Packit Service |
a4b2a9 |
if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "setenv failed with %d", errno);
|
|
Packit Service |
a4b2a9 |
krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_successful = 1;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "Kerberos authentication was successful!");
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Attempt to bind to the ldap server using a given authentication
|
|
Packit Service |
a4b2a9 |
* mechanism. ldap should be a properly initialzed ldap pointer.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Returns a valid sasl_conn_t pointer upon success, NULL on failure.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
sasl_conn_t *
|
|
Packit Service |
a4b2a9 |
sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *mech)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
sasl_conn_t *conn;
|
|
Packit Service |
a4b2a9 |
char *tmp, *host = NULL;
|
|
Packit Service |
a4b2a9 |
const char *clientout;
|
|
Packit Service |
a4b2a9 |
unsigned int clientoutlen;
|
|
Packit Service |
a4b2a9 |
const char *chosen_mech;
|
|
Packit Service |
a4b2a9 |
int result;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!strncmp(mech, "GSSAPI", 6)) {
|
|
Packit Service |
a4b2a9 |
if (ctxt->client_cc)
|
|
Packit Service |
a4b2a9 |
result = sasl_do_kinit_ext_cc(logopt, ctxt);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
result = sasl_do_kinit(logopt, ctxt);
|
|
Packit Service |
a4b2a9 |
if (result != 0)
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "Attempting sasl bind with mechanism %s", mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
|
|
Packit Service |
a4b2a9 |
if (result != LDAP_OPT_SUCCESS || !host) {
|
|
Packit Service |
a4b2a9 |
debug(logopt, "failed to get hostname for connection");
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* We need a host name to start the client.
|
|
Packit Service |
a4b2a9 |
* But the ldap library can return a list of host names so
|
|
Packit Service |
a4b2a9 |
* just use the first one.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if ((tmp = strchr(host, ' ')))
|
|
Packit Service |
a4b2a9 |
*tmp = '\0';
|
|
Packit Service |
a4b2a9 |
if ((tmp = strrchr(host, ':'))) {
|
|
Packit Service |
a4b2a9 |
if (*(tmp - 1) != ']') {
|
|
Packit Service |
a4b2a9 |
*tmp = '\0';
|
|
Packit Service |
a4b2a9 |
tmp = host;
|
|
Packit Service |
a4b2a9 |
} else {
|
|
Packit Service |
a4b2a9 |
*(tmp - 1) = '\0';
|
|
Packit Service |
a4b2a9 |
tmp = host;
|
|
Packit Service |
a4b2a9 |
if (*tmp == '[')
|
|
Packit Service |
a4b2a9 |
tmp++;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Create a new authentication context for the service. */
|
|
Packit Service |
a4b2a9 |
result = sasl_client_new("ldap", tmp, NULL, NULL, NULL, 0, &conn;;
|
|
Packit Service |
a4b2a9 |
if (result != SASL_OK) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "sasl_client_new failed with error %d",
|
|
Packit Service |
a4b2a9 |
result);
|
|
Packit Service |
a4b2a9 |
ldap_memfree(host);
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
chosen_mech = NULL;
|
|
Packit Service |
a4b2a9 |
result = sasl_client_start(conn, mech, NULL,
|
|
Packit Service |
a4b2a9 |
&clientout, &clientoutlen, &chosen_mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* OK and CONTINUE are the only non-fatal return codes here. */
|
|
Packit Service |
a4b2a9 |
if ((result != SASL_OK) && (result != SASL_CONTINUE)) {
|
|
Packit Service |
a4b2a9 |
warn(logopt, "sasl_client_start failed for %s", host);
|
|
Packit Service |
a4b2a9 |
debug(logopt, "sasl_client_start: %s", sasl_errdetail(conn));
|
|
Packit Service |
a4b2a9 |
ldap_memfree(host);
|
|
Packit Service |
a4b2a9 |
sasl_dispose(&conn;;
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
result = do_sasl_bind(logopt, ldap, conn,
|
|
Packit Service |
a4b2a9 |
&clientout, &clientoutlen, chosen_mech, result);
|
|
Packit Service |
a4b2a9 |
if (result == 0) {
|
|
Packit Service |
a4b2a9 |
ldap_memfree(host);
|
|
Packit Service |
a4b2a9 |
debug(logopt, "sasl bind with mechanism %s succeeded",
|
|
Packit Service |
a4b2a9 |
chosen_mech);
|
|
Packit Service |
a4b2a9 |
return conn;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
info(logopt, "sasl bind with mechanism %s failed", mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* sasl bind failed */
|
|
Packit Service |
a4b2a9 |
ldap_memfree(host);
|
|
Packit Service |
a4b2a9 |
sasl_dispose(&conn;;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Returns 0 if a suitable authentication mechanism is available. Returns
|
|
Packit Service |
a4b2a9 |
* -1 on error or if no mechanism is supported by both client and server.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
sasl_conn_t *
|
|
Packit Service |
a4b2a9 |
sasl_choose_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
sasl_conn_t *conn = NULL;
|
|
Packit Service |
a4b2a9 |
int authenticated;
|
|
Packit Service |
a4b2a9 |
int i;
|
|
Packit Service |
a4b2a9 |
char **mechanisms;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
mechanisms = get_server_SASL_mechanisms(logopt, ldap);
|
|
Packit Service |
a4b2a9 |
if (!mechanisms)
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Try each supported mechanism in turn. */
|
|
Packit Service |
a4b2a9 |
authenticated = 0;
|
|
Packit Service |
a4b2a9 |
for (i = 0; mechanisms[i] != NULL; i++) {
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* This routine is called if there is no configured
|
|
Packit Service |
a4b2a9 |
* mechanism. As such, we can skip over any auth
|
|
Packit Service |
a4b2a9 |
* mechanisms that require user credentials. These include
|
|
Packit Service |
a4b2a9 |
* PLAIN, LOGIN, and DIGEST-MD5.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if (authtype_requires_creds(mechanisms[i]))
|
|
Packit Service |
a4b2a9 |
continue;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
conn = sasl_bind_mech(logopt, ldap, ctxt, mechanisms[i]);
|
|
Packit Service |
a4b2a9 |
if (conn) {
|
|
Packit Service |
a4b2a9 |
ctxt->sasl_mech = strdup(mechanisms[i]);
|
|
Packit Service |
a4b2a9 |
if (!ctxt->sasl_mech) {
|
|
Packit Service |
a4b2a9 |
crit(logopt, "Successfully authenticated with "
|
|
Packit Service |
a4b2a9 |
"mechanism %s, but failed to allocate "
|
|
Packit Service |
a4b2a9 |
"memory to hold the mechanism type.",
|
|
Packit Service |
a4b2a9 |
mechanisms[i]);
|
|
Packit Service |
a4b2a9 |
sasl_dispose(&conn;;
|
|
Packit Service |
a4b2a9 |
ldap_value_free(mechanisms);
|
|
Packit Service |
a4b2a9 |
return NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
authenticated = 1;
|
|
Packit Service |
a4b2a9 |
break;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
debug(logopt, "Failed to authenticate with mech %s",
|
|
Packit Service |
a4b2a9 |
mechanisms[i]);
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt, "authenticated: %d, sasl_mech: %s",
|
|
Packit Service |
a4b2a9 |
authenticated, ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ldap_value_free(mechanisms);
|
|
Packit Service |
a4b2a9 |
return conn;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Routine called when unbinding an ldap connection.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
void
|
|
Packit Service |
a4b2a9 |
autofs_sasl_unbind(struct ldap_conn *conn, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
|
|
Packit Service |
a4b2a9 |
if (conn->ldap) {
|
|
Packit Service |
a4b2a9 |
ldap_unbind_s(conn->ldap);
|
|
Packit Service |
a4b2a9 |
conn->ldap = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (conn->sasl_conn) {
|
|
Packit Service |
a4b2a9 |
sasl_dispose(&conn->sasl_conn);
|
|
Packit Service |
a4b2a9 |
conn->sasl_conn = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Given a lookup context that has been initialized with any user-specified
|
|
Packit Service |
a4b2a9 |
* parameters, figure out which sasl mechanism to use. Then, initialize
|
|
Packit Service |
a4b2a9 |
* the necessary parameters to authenticate with the chosen mechanism.
|
|
Packit Service |
a4b2a9 |
*
|
|
Packit Service |
a4b2a9 |
* Return Values:
|
|
Packit Service |
a4b2a9 |
* 0 - Success
|
|
Packit Service |
a4b2a9 |
* -1 - Failure
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
int
|
|
Packit Service |
a4b2a9 |
autofs_sasl_bind(unsigned logopt,
|
|
Packit Service |
a4b2a9 |
struct ldap_conn *conn, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
sasl_conn_t *sasl_conn = NULL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
|
|
Packit Service |
a4b2a9 |
int result;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"Attempting sasl bind with mechanism %s",
|
|
Packit Service |
a4b2a9 |
ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
result = do_sasl_extern(conn->ldap, ctxt);
|
|
Packit Service |
a4b2a9 |
if (result)
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"Failed to authenticate with mech %s",
|
|
Packit Service |
a4b2a9 |
ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
debug(logopt,
|
|
Packit Service |
a4b2a9 |
"sasl bind with mechanism %s succeeded",
|
|
Packit Service |
a4b2a9 |
ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return result;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
sasl_auth_id = ctxt->user;
|
|
Packit Service |
a4b2a9 |
sasl_auth_secret = ctxt->secret;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) {
|
|
Packit Service |
a4b2a9 |
if (ctxt->sasl_mech) {
|
|
Packit Service |
a4b2a9 |
free(ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
ctxt->sasl_mech = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* If LDAP_AUTH_AUTODETECT is set, it means that there was no
|
|
Packit Service |
a4b2a9 |
* mechanism specified in the configuration file or auto
|
|
Packit Service |
a4b2a9 |
* selection has been requested, so try to auto-select an
|
|
Packit Service |
a4b2a9 |
* auth mechanism.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
if (ctxt->sasl_mech)
|
|
Packit Service |
a4b2a9 |
sasl_conn = sasl_bind_mech(logopt,
|
|
Packit Service |
a4b2a9 |
conn->ldap, ctxt, ctxt->sasl_mech);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
sasl_conn = sasl_choose_mech(logopt, conn->ldap, ctxt);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!sasl_conn)
|
|
Packit Service |
a4b2a9 |
return -1;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
conn->sasl_conn = sasl_conn;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Destructor routine. This should be called when finished with an ldap
|
|
Packit Service |
a4b2a9 |
* session.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
void autofs_sasl_dispose(struct ldap_conn *conn, struct lookup_context *ctxt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int status, ret;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
|
|
Packit Service |
a4b2a9 |
if (conn && conn->ldap) {
|
|
Packit Service |
a4b2a9 |
ldap_unbind_s(conn->ldap);
|
|
Packit Service |
a4b2a9 |
conn->ldap = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (conn && conn->sasl_conn) {
|
|
Packit Service |
a4b2a9 |
sasl_dispose(&conn->sasl_conn);
|
|
Packit Service |
a4b2a9 |
conn->sasl_conn = NULL;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (ctxt->kinit_successful) {
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_lock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (--krb5cc_in_use || ctxt->client_cc)
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
else
|
|
Packit Service |
a4b2a9 |
ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
|
|
Packit Service |
a4b2a9 |
if (ret)
|
|
Packit Service |
a4b2a9 |
logmsg("krb5_cc_destroy failed with non-fatal error %d",
|
|
Packit Service |
a4b2a9 |
ret);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
status = pthread_mutex_unlock(&krb5cc_mutex);
|
|
Packit Service |
a4b2a9 |
if (status)
|
|
Packit Service |
a4b2a9 |
fatal(status);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
krb5_free_context(ctxt->krb5ctxt);
|
|
Packit Service |
a4b2a9 |
if (unsetenv(krb5ccenv) != 0)
|
|
Packit Service |
a4b2a9 |
logerr("unsetenv failed with error %d", errno);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
ctxt->krb5ctxt = NULL;
|
|
Packit Service |
a4b2a9 |
ctxt->krb5_ccache = NULL;
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_done = 0;
|
|
Packit Service |
a4b2a9 |
ctxt->kinit_successful = 0;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static void *sasl_mutex_new(void)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
pthread_mutex_t* mutex;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
mutex = malloc(sizeof(pthread_mutex_t));
|
|
Packit Service |
a4b2a9 |
if (!mutex)
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
pthread_mutex_init(mutex, NULL);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return (void *) mutex;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static int sasl_mutex_lock(void *mutex __attribute__((unused)))
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int rc;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!mutex)
|
|
Packit Service |
a4b2a9 |
return SASL_FAIL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
rc = pthread_mutex_lock((pthread_mutex_t *) mutex);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return (rc==0 ? SASL_OK : SASL_FAIL);
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int rc;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!mutex)
|
|
Packit Service |
a4b2a9 |
return SASL_FAIL;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
rc = pthread_mutex_unlock((pthread_mutex_t *) mutex);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return (rc==0 ? SASL_OK : SASL_FAIL);
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
static void sasl_mutex_dispose(void *mutex __attribute__((unused)))
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
int rc;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
if (!mutex)
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
rc = pthread_mutex_destroy((pthread_mutex_t *) mutex);
|
|
Packit Service |
a4b2a9 |
if (rc == 0)
|
|
Packit Service |
a4b2a9 |
free(mutex);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Initialize the sasl callbacks, which increments the global
|
|
Packit Service |
a4b2a9 |
* use counter.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
int autofs_sasl_client_init(unsigned logopt)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
sasl_set_mutex(sasl_mutex_new,
|
|
Packit Service |
a4b2a9 |
sasl_mutex_lock,
|
|
Packit Service |
a4b2a9 |
sasl_mutex_unlock,
|
|
Packit Service |
a4b2a9 |
sasl_mutex_dispose);
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/* Start up Cyrus SASL--only needs to be done at library load. */
|
|
Packit Service |
a4b2a9 |
if (sasl_client_init(callbacks) != SASL_OK) {
|
|
Packit Service |
a4b2a9 |
error(logopt, "sasl_client_init failed");
|
|
Packit Service |
a4b2a9 |
return 0;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
return 1;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|
|
Packit Service |
a4b2a9 |
/*
|
|
Packit Service |
a4b2a9 |
* Decrement the library reference count and free resources if
|
|
Packit Service |
a4b2a9 |
* we are the last to close the library.
|
|
Packit Service |
a4b2a9 |
*/
|
|
Packit Service |
a4b2a9 |
void autofs_sasl_done(void)
|
|
Packit Service |
a4b2a9 |
{
|
|
Packit Service |
a4b2a9 |
sasl_done();
|
|
Packit Service |
a4b2a9 |
return;
|
|
Packit Service |
a4b2a9 |
}
|
|
Packit Service |
a4b2a9 |
|