krb5_set_password: Use target principal for SOCKS4a userid.
This enables Tor stream isolation.
This commit is contained in:
committed by
Nicolas Williams
parent
5c5cb66c05
commit
c768567929
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
#include "krb5_locl.h"
|
||||
#include "socks4a.h"
|
||||
|
||||
#undef __attribute__
|
||||
#define __attribute__(X)
|
||||
@@ -501,6 +502,38 @@ static const struct kpwd_proc {
|
||||
{ NULL, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Proxy I/O
|
||||
*/
|
||||
|
||||
static int
|
||||
chgpw_socks4a_read(void *vcontext, void *vsockp, void *buf, unsigned len)
|
||||
{
|
||||
int *sockp = vsockp;
|
||||
|
||||
return recv(*sockp, buf, len, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
chgpw_socks4a_write(void *vcontext, void *vsockp, const void *buf,
|
||||
unsigned len)
|
||||
{
|
||||
int *sockp = vsockp;
|
||||
|
||||
return send(*sockp, buf, len, 0);
|
||||
}
|
||||
|
||||
static struct socks4a_io
|
||||
chgpw_socks4a_io(int *sockp)
|
||||
{
|
||||
|
||||
return (struct socks4a_io) {
|
||||
.sio_cookie = sockp,
|
||||
.sio_read = &chgpw_socks4a_read,
|
||||
.sio_write = &chgpw_socks4a_write,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
@@ -519,6 +552,8 @@ change_password_loop (krb5_context context,
|
||||
krb5_auth_context auth_context = NULL;
|
||||
krb5_krbhst_handle handle = NULL;
|
||||
krb5_krbhst_info *hi;
|
||||
struct addrinfo *proxy_ai = NULL;
|
||||
char *proxy_userid = NULL;
|
||||
rk_socket_t sock;
|
||||
unsigned int i;
|
||||
int done = 0;
|
||||
@@ -540,6 +575,62 @@ change_password_loop (krb5_context context,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If we're configured to talk through a SOCKS4a proxy, resolve its
|
||||
* address first so we can reuse it in the loop over hosts.
|
||||
*/
|
||||
if (context->socks4a_proxy) {
|
||||
char *proxy, *proxyhost, *proxyport;
|
||||
struct addrinfo hints;
|
||||
|
||||
/*
|
||||
* Parse `<host>[:<port>]' into parts.
|
||||
*/
|
||||
if ((proxy = strdup(context->socks4a_proxy)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
proxyhost = proxy;
|
||||
if ((proxyport = strchr(proxy, ':')) != NULL)
|
||||
*proxyport++ = '\0';
|
||||
|
||||
/*
|
||||
* Set up getaddrinfo hints for stream connection.
|
||||
*/
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/*
|
||||
* If block_dns is enabled, make sure AI_CANONNAME is clear and
|
||||
* AI_NUMERICHOST|AI_NUMERICSERV are both set to avoid the
|
||||
* potential for DNS leaks.
|
||||
*/
|
||||
if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns",
|
||||
NULL)) {
|
||||
hints.ai_flags &= ~AI_CANONNAME;
|
||||
hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve the proxy's address.
|
||||
*/
|
||||
ret = getaddrinfo(proxyhost, proxyport ? proxyport : "1080", &hints,
|
||||
&proxy_ai);
|
||||
free(proxy);
|
||||
if (ret) {
|
||||
ret = krb5_eai_to_heim_errno(ret, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the userid for stream isolation.
|
||||
*/
|
||||
ret = krb5_unparse_name(context, targprinc, &proxy_userid);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
|
||||
struct addrinfo *ai, *a;
|
||||
int is_stream;
|
||||
@@ -577,6 +668,55 @@ change_password_loop (krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's a SOCKS4a proxy in the way, we need the proxy
|
||||
* to connect to the real host before we can continue.
|
||||
*/
|
||||
if (context->socks4a_proxy) {
|
||||
struct socks4a *socks4a;
|
||||
|
||||
/*
|
||||
* Set up the SOCKS4a proxy connection request.
|
||||
*/
|
||||
ret = _krb5_socks4a_connect(chgpw_socks4a_io(&sock),
|
||||
hi->hostname, hi->port, proxy_userid, &socks4a);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Until the SOCKS4a connection has succeeeded, wait
|
||||
* until we can read or write as needed by SOCKS4a and
|
||||
* do the SOCKS4a I/O.
|
||||
*/
|
||||
while (!_krb5_socks4a_connected(socks4a)) {
|
||||
fd_set readfds, writefds;
|
||||
int nready;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
if (_krb5_socks4a_reading(socks4a))
|
||||
FD_SET(sock, &readfds);
|
||||
if (_krb5_socks4a_writing(socks4a))
|
||||
FD_SET(sock, &writefds);
|
||||
nready = select(sock + 1, &readfds, &writefds,
|
||||
/*exceptfds*/NULL, /*timeout*/NULL);
|
||||
if (nready == -1) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
if (nready <= 0) {
|
||||
ret = EIO; /* timeout should be impossible */
|
||||
break;
|
||||
}
|
||||
ret = _krb5_socks4a_io(socks4a);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
_krb5_socks4a_free(socks4a);
|
||||
if (ret)
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = krb5_auth_con_genaddrs (context, auth_context, sock,
|
||||
KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
|
||||
if (ret) {
|
||||
@@ -649,6 +789,10 @@ change_password_loop (krb5_context context,
|
||||
out:
|
||||
krb5_krbhst_free (context, handle);
|
||||
krb5_auth_con_free (context, auth_context);
|
||||
if (proxy_ai)
|
||||
freeaddrinfo(proxy_ai);
|
||||
if (proxy_userid)
|
||||
free(proxy_userid);
|
||||
|
||||
if (ret == KRB5_KDC_UNREACH) {
|
||||
krb5_set_error_message(context,
|
||||
|
||||
Reference in New Issue
Block a user