|
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); |