krb5_set_password: Use target principal for SOCKS4a userid.

This enables Tor stream isolation.
This commit is contained in:
Taylor R Campbell
2024-01-02 22:59:43 +00:00
committed by Nicolas Williams
parent 5c5cb66c05
commit c768567929

View File

@@ -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,