version 1.1.1.4, 2013/07/22 10:46:12
|
version 1.1.1.5, 2013/10/14 07:56:34
|
Line 43
|
Line 43
|
# include <time.h> |
# include <time.h> |
#endif |
#endif |
#include <ctype.h> |
#include <ctype.h> |
|
#include <fcntl.h> |
#include <pwd.h> |
#include <pwd.h> |
#include <grp.h> |
#include <grp.h> |
#include <netinet/in.h> |
#include <netinet/in.h> |
Line 62
|
Line 63
|
# else |
# else |
# include <sasl.h> |
# include <sasl.h> |
# endif |
# endif |
# if HAVE_GSS_KRB5_CCACHE_NAME | # ifdef HAVE_DLOPEN |
# if defined(HAVE_GSSAPI_GSSAPI_KRB5_H) | # include <dlfcn.h> |
# include <gssapi/gssapi.h> | # else |
# include <gssapi/gssapi_krb5.h> | # include "compat/dlfcn.h" |
# elif defined(HAVE_GSSAPI_GSSAPI_H) | |
# include <gssapi/gssapi.h> | |
# else | |
# include <gssapi.h> | |
# endif | |
# endif |
# endif |
#endif | #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ |
|
|
#include "sudoers.h" |
#include "sudoers.h" |
#include "parse.h" |
#include "parse.h" |
Line 603 sudo_ldap_init(LDAP **ldp, const char *host, int port)
|
Line 599 sudo_ldap_init(LDAP **ldp, const char *host, int port)
|
} else |
} else |
#elif defined(HAVE_LDAP_SSL_INIT) && defined(HAVE_LDAP_SSL_CLIENT_INIT) |
#elif defined(HAVE_LDAP_SSL_INIT) && defined(HAVE_LDAP_SSL_CLIENT_INIT) |
if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { |
if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { |
if (ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, 0, &rc) != LDAP_SUCCESS) { | int sslrc; |
warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc)); | rc = ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, |
| 0, &sslrc); |
| if (rc != LDAP_SUCCESS) { |
| warningx("ldap_ssl_client_init(): %s (SSL reason code %d)", |
| ldap_err2string(rc), sslrc); |
debug_return_int(-1); |
debug_return_int(-1); |
} |
} |
DPRINTF2("ldap_ssl_init(%s, %d, NULL)", host, port); |
DPRINTF2("ldap_ssl_init(%s, %d, NULL)", host, port); |
Line 1441 sudo_ldap_parse_keyword(const char *keyword, const cha
|
Line 1441 sudo_ldap_parse_keyword(const char *keyword, const cha
|
debug_return_bool(false); |
debug_return_bool(false); |
} |
} |
|
|
|
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
|
static const char * |
|
sudo_krb5_ccname_path(const char *old_ccname) |
|
{ |
|
const char *ccname = old_ccname; |
|
debug_decl(sudo_krb5_ccname_path, SUDO_DEBUG_LDAP) |
|
|
|
/* Strip off leading FILE: or WRFILE: prefix. */ |
|
switch (ccname[0]) { |
|
case 'F': |
|
case 'f': |
|
if (strncasecmp(ccname, "FILE:", 5) == 0) |
|
ccname += 5; |
|
break; |
|
case 'W': |
|
case 'w': |
|
if (strncasecmp(ccname, "WRFILE:", 7) == 0) |
|
ccname += 7; |
|
break; |
|
} |
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
|
"ccache %s -> %s", old_ccname, ccname); |
|
|
|
/* Credential cache must be a fully-qualified path name. */ |
|
debug_return_str(*ccname == '/' ? ccname : NULL); |
|
} |
|
|
static bool |
static bool |
|
sudo_check_krb5_ccname(const char *ccname) |
|
{ |
|
int fd = -1; |
|
const char *ccname_path; |
|
debug_decl(sudo_check_krb5_ccname, SUDO_DEBUG_LDAP) |
|
|
|
/* Strip off prefix to get path name. */ |
|
ccname_path = sudo_krb5_ccname_path(ccname); |
|
if (ccname_path == NULL) { |
|
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, |
|
"unsupported krb5 credential cache path: %s", ccname); |
|
debug_return_bool(false); |
|
} |
|
/* Make sure credential cache is fully-qualified and exists. */ |
|
fd = open(ccname_path, O_RDONLY|O_NONBLOCK, 0); |
|
if (fd == -1) { |
|
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, |
|
"unable to open krb5 credential cache: %s", ccname_path); |
|
debug_return_bool(false); |
|
} |
|
close(fd); |
|
sudo_debug_printf(SUDO_DEBUG_INFO, |
|
"using krb5 credential cache: %s", ccname_path); |
|
debug_return_bool(true); |
|
} |
|
#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ |
|
|
|
static bool |
sudo_ldap_read_config(void) |
sudo_ldap_read_config(void) |
{ |
{ |
FILE *fp; |
FILE *fp; |
Line 1642 sudo_ldap_read_config(void)
|
Line 1697 sudo_ldap_read_config(void)
|
* Make sure we can open the file specified by krb5_ccname. |
* Make sure we can open the file specified by krb5_ccname. |
*/ |
*/ |
if (ldap_conf.krb5_ccname != NULL) { |
if (ldap_conf.krb5_ccname != NULL) { |
if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 || | if (!sudo_check_krb5_ccname(ldap_conf.krb5_ccname)) |
strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) { | ldap_conf.krb5_ccname = NULL; |
value = ldap_conf.krb5_ccname + | |
(ldap_conf.krb5_ccname[4] == ':' ? 5 : 7); | |
if ((fp = fopen(value, "r")) != NULL) { | |
sudo_debug_printf(SUDO_DEBUG_INFO, | |
"using krb5 credential cache: %s", value); | |
fclose(fp); | |
} else { | |
/* Can't open it, just ignore the entry. */ | |
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, | |
"unable to open krb5 credential cache: %s", value); | |
efree(ldap_conf.krb5_ccname); | |
ldap_conf.krb5_ccname = NULL; | |
} | |
} | |
} |
} |
#endif |
#endif |
|
|
debug_return_bool(true); |
debug_return_bool(true); |
} |
} |
|
|
Line 1982 done:
|
Line 2024 done:
|
} |
} |
|
|
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
|
static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name); |
|
|
static int |
static int |
|
sudo_set_krb5_ccache_name(const char *name, const char **old_name) |
|
{ |
|
int rc = 0; |
|
unsigned int junk; |
|
static bool initialized; |
|
debug_decl(sudo_set_krb5_ccache_name, SUDO_DEBUG_LDAP) |
|
|
|
if (!initialized) { |
|
sudo_gss_krb5_ccache_name = dlsym(RTLD_DEFAULT, "gss_krb5_ccache_name"); |
|
initialized = true; |
|
} |
|
|
|
/* |
|
* Try to use gss_krb5_ccache_name() if possible. |
|
* We also need to set KRB5CCNAME since some LDAP libs may not use |
|
* gss_krb5_ccache_name(). |
|
*/ |
|
if (sudo_gss_krb5_ccache_name != NULL) { |
|
rc = sudo_gss_krb5_ccache_name(&junk, name, old_name); |
|
} else { |
|
/* No gss_krb5_ccache_name(), fall back on KRB5CCNAME. */ |
|
if (old_name != NULL) |
|
*old_name = sudo_getenv("KRB5CCNAME"); |
|
} |
|
if (name != NULL && *name != '\0') |
|
sudo_setenv("KRB5CCNAME", name, true); |
|
else |
|
sudo_unsetenv("KRB5CCNAME"); |
|
|
|
debug_return_int(rc); |
|
} |
|
|
|
/* |
|
* Make a copy of the credential cache file specified by KRB5CCNAME |
|
* which must be readable by the user. The resulting cache file |
|
* is root-owned and will be removed after authenticating via SASL. |
|
*/ |
|
static char * |
|
sudo_krb5_copy_cc_file(const char *old_ccname) |
|
{ |
|
int ofd, nfd; |
|
ssize_t nread, nwritten = -1; |
|
static char new_ccname[sizeof(_PATH_TMP) + sizeof("sudocc_XXXXXXXX") - 1]; |
|
char buf[10240], *ret = NULL; |
|
debug_decl(sudo_krb5_copy_cc_file, SUDO_DEBUG_LDAP) |
|
|
|
old_ccname = sudo_krb5_ccname_path(old_ccname); |
|
if (old_ccname != NULL) { |
|
/* Open credential cache as user to prevent stolen creds. */ |
|
set_perms(PERM_USER); |
|
ofd = open(old_ccname, O_RDONLY|O_NONBLOCK); |
|
restore_perms(); |
|
|
|
if (ofd != -1) { |
|
(void) fcntl(ofd, F_SETFL, 0); |
|
if (lock_file(ofd, SUDO_LOCK)) { |
|
snprintf(new_ccname, sizeof(new_ccname), "%s%s", |
|
_PATH_TMP, "sudocc_XXXXXXXX"); |
|
nfd = mkstemp(new_ccname); |
|
if (nfd != -1) { |
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
|
"copy ccache %s -> %s", old_ccname, new_ccname); |
|
while ((nread = read(ofd, buf, sizeof(buf))) > 0) { |
|
ssize_t off = 0; |
|
do { |
|
nwritten = write(nfd, buf + off, nread - off); |
|
if (nwritten == -1) { |
|
warning("error writing to %s", new_ccname); |
|
goto write_error; |
|
} |
|
off += nwritten; |
|
} while (off < nread); |
|
} |
|
if (nread == -1) |
|
warning("unable to read %s", new_ccname); |
|
write_error: |
|
close(nfd); |
|
if (nread != -1 && nwritten != -1) { |
|
ret = new_ccname; /* success! */ |
|
} else { |
|
unlink(new_ccname); /* failed */ |
|
} |
|
} else { |
|
warning("unable to create temp file %s", new_ccname); |
|
} |
|
} |
|
close(ofd); |
|
} else { |
|
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, |
|
"unable to open %s", old_ccname); |
|
} |
|
} |
|
debug_return_str(ret); |
|
} |
|
|
|
static int |
sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id, |
sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id, |
void *_interact) |
void *_interact) |
{ |
{ |
char *auth_id = (char *)_auth_id; |
char *auth_id = (char *)_auth_id; |
sasl_interact_t *interact = (sasl_interact_t *)_interact; |
sasl_interact_t *interact = (sasl_interact_t *)_interact; |
|
int rc = LDAP_SUCCESS; |
debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP) |
debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP) |
|
|
for (; interact->id != SASL_CB_LIST_END; interact++) { |
for (; interact->id != SASL_CB_LIST_END; interact++) { |
if (interact->id != SASL_CB_USER) | if (interact->id != SASL_CB_USER) { |
debug_return_int(LDAP_PARAM_ERROR); | warningx("sudo_ldap_sasl_interact: unexpected interact id %lu", |
| interact->id); |
| rc = LDAP_PARAM_ERROR; |
| break; |
| } |
|
|
if (auth_id != NULL) |
if (auth_id != NULL) |
interact->result = auth_id; |
interact->result = auth_id; |
Line 2003 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags,
|
Line 2148 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags,
|
|
|
interact->len = strlen(interact->result); |
interact->len = strlen(interact->result); |
#if SASL_VERSION_MAJOR < 2 |
#if SASL_VERSION_MAJOR < 2 |
interact->result = estrdup(interact->result); | interact->result = strdup(interact->result); |
| if (interact->result == NULL) { |
| rc = LDAP_NO_MEMORY; |
| break; |
| } |
#endif /* SASL_VERSION_MAJOR < 2 */ |
#endif /* SASL_VERSION_MAJOR < 2 */ |
|
DPRINTF2("sudo_ldap_sasl_interact: SASL_CB_USER %s", |
|
(const char *)interact->result); |
} |
} |
debug_return_int(LDAP_SUCCESS); | debug_return_int(rc); |
} |
} |
#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ |
#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ |
|
|
|
|
/* |
/* |
* Set LDAP options from the specified options table |
* Set LDAP options from the specified options table |
*/ |
*/ |
Line 2212 static int
|
Line 2362 static int
|
sudo_ldap_bind_s(LDAP *ld) |
sudo_ldap_bind_s(LDAP *ld) |
{ |
{ |
int rc; |
int rc; |
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
|
const char *old_ccname = user_ccname; |
|
# ifdef HAVE_GSS_KRB5_CCACHE_NAME |
|
unsigned int status; |
|
# endif |
|
#endif |
|
debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP) |
debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP) |
|
|
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S |
if (ldap_conf.rootuse_sasl == true || |
if (ldap_conf.rootuse_sasl == true || |
(ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) { |
(ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) { |
|
const char *old_ccname = NULL; |
|
const char *new_ccname = ldap_conf.krb5_ccname; |
|
const char *tmp_ccname = NULL; |
void *auth_id = ldap_conf.rootsasl_auth_id ? |
void *auth_id = ldap_conf.rootsasl_auth_id ? |
ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id; |
ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id; |
|
|
if (ldap_conf.krb5_ccname != NULL) { | /* Make temp copy of the user's credential cache as needed. */ |
# ifdef HAVE_GSS_KRB5_CCACHE_NAME | if (ldap_conf.krb5_ccname == NULL && user_ccname != NULL) { |
if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname) | new_ccname = tmp_ccname = sudo_krb5_copy_cc_file(user_ccname); |
!= GSS_S_COMPLETE) { | if (tmp_ccname == NULL) { |
old_ccname = NULL; | sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
| "unable to copy user ccache %s", user_ccname); |
| } |
| } |
| |
| if (new_ccname != NULL) { |
| rc = sudo_set_krb5_ccache_name(new_ccname, &old_ccname); |
| if (rc == 0) { |
| sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
| "set ccache name %s -> %s", |
| old_ccname ? old_ccname : "(none)", new_ccname); |
| } else { |
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, |
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, |
"gss_krb5_ccache_name() failed: %d", status); | "gss_krb5_ccache_name() failed: %d", rc); |
} |
} |
# else |
|
sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, true); |
|
# endif |
|
} |
} |
rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI", |
rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI", |
NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id); |
NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id); |
if (ldap_conf.krb5_ccname != NULL) { | if (new_ccname != NULL) { |
# ifdef HAVE_GSS_KRB5_CCACHE_NAME | rc = sudo_set_krb5_ccache_name(old_ccname, NULL); |
if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE) | if (rc == 0) { |
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, | sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, |
"gss_krb5_ccache_name() failed: %d", status); | "restore ccache name %s -> %s", new_ccname, old_ccname); |
# else | } else { |
if (old_ccname != NULL) | sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, |
sudo_setenv("KRB5CCNAME", old_ccname, true); | "gss_krb5_ccache_name() failed: %d", rc); |
else | } |
sudo_unsetenv("KRB5CCNAME"); | /* Remove temporary copy of user's credential cache. */ |
# endif | if (tmp_ccname != NULL) |
| unlink(tmp_ccname); |
} |
} |
if (rc != LDAP_SUCCESS) { |
if (rc != LDAP_SUCCESS) { |
warningx("ldap_sasl_interactive_bind_s(): %s", |
warningx("ldap_sasl_interactive_bind_s(): %s", |
Line 2345 sudo_ldap_open(struct sudo_nss *nss)
|
Line 2501 sudo_ldap_open(struct sudo_nss *nss)
|
} |
} |
DPRINTF1("ldap_start_tls_s() ok"); |
DPRINTF1("ldap_start_tls_s() ok"); |
#elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP) |
#elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP) |
if (ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, 0, &rc) != LDAP_SUCCESS) { | int sslrc; |
warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc)); | rc = ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, |
| 0, &sslrc); |
| if (rc != LDAP_SUCCESS) { |
| warningx("ldap_ssl_client_init(): %s (SSL reason code %d)", |
| ldap_err2string(rc), sslrc); |
debug_return_int(-1); |
debug_return_int(-1); |
} |
} |
rc = ldap_start_tls_s_np(ld, NULL); |
rc = ldap_start_tls_s_np(ld, NULL); |