(main): use getarg

(*): handle v4 and/or v5


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@6183 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Assar Westerlund
1999-05-10 00:16:50 +00:00
parent fc92108367
commit 3447488a94
2 changed files with 439 additions and 345 deletions

View File

@@ -97,39 +97,34 @@ usr2handler (int sig)
*/ */
static int static int
connect_host (char *host, char *user, des_cblock *key, connect_host (kx_context *kc)
des_key_schedule schedule, int port,
struct sockaddr_in *thisaddr,
struct sockaddr_in *thataddr)
{ {
CREDENTIALS cred;
KTEXT_ST text;
MSG_DAT msg;
int status;
int addrlen; int addrlen;
struct hostent *hostent; struct hostent *hostent;
int s; int s;
char **p; char **p;
struct sockaddr_in thisaddr;
struct sockaddr_in thataddr;
hostent = gethostbyname (host); hostent = gethostbyname (kc->host);
if (hostent == NULL) { if (hostent == NULL) {
warnx ("gethostbyname '%s' failed: %s", host, warnx ("gethostbyname '%s' failed: %s", kc->host,
hstrerror(h_errno)); hstrerror(h_errno));
return -1; return -1;
} }
memset (thataddr, 0, sizeof(*thataddr)); memset (&thataddr, 0, sizeof(thataddr));
thataddr->sin_family = AF_INET; thataddr.sin_family = AF_INET;
thataddr->sin_port = port; thataddr.sin_port = kc->port;
for(p = hostent->h_addr_list; *p; ++p) { for(p = hostent->h_addr_list; *p; ++p) {
memcpy (&thataddr->sin_addr, *p, sizeof(thataddr->sin_addr)); memcpy (&thataddr.sin_addr, *p, sizeof(thataddr.sin_addr));
s = socket (AF_INET, SOCK_STREAM, 0); s = socket (AF_INET, SOCK_STREAM, 0);
if (s < 0) if (s < 0)
err (1, "socket"); err (1, "socket");
if (connect (s, (struct sockaddr *)thataddr, sizeof(*thataddr)) < 0) { if (connect (s, (struct sockaddr *)&thataddr, sizeof(thataddr)) < 0) {
warn ("connect(%s)", host); warn ("connect(%s)", kc->host);
close (s); close (s);
continue; continue;
} else { } else {
@@ -139,19 +134,14 @@ connect_host (char *host, char *user, des_cblock *key,
if (*p == NULL) if (*p == NULL)
return -1; return -1;
addrlen = sizeof(*thisaddr); addrlen = sizeof(thisaddr);
if (getsockname (s, (struct sockaddr *)thisaddr, &addrlen) < 0 || if (getsockname (s, (struct sockaddr *)&thisaddr, &addrlen) < 0 ||
addrlen != sizeof(*thisaddr)) addrlen != sizeof(thisaddr))
err(1, "getsockname(%s)", host); err(1, "getsockname(%s)", kc->host);
status = krb_sendauth (KOPT_DO_MUTUAL, s, &text, "rcmd", kc->thisaddr = thisaddr;
host, krb_realmofhost (host), kc->thataddr = thataddr;
getpid(), &msg, &cred, schedule, if ((*kc->authenticate)(kc, s))
thisaddr, thataddr, KX_VERSION);
if (status != KSUCCESS) {
warnx ("%s: %s\n", host, krb_get_err_text(status));
return -1; return -1;
}
memcpy(key, cred.session, sizeof(des_cblock));
return s; return s;
} }
@@ -161,23 +151,21 @@ connect_host (char *host, char *user, des_cblock *key,
*/ */
static int static int
passive_session (int xserver, int fd, des_cblock *iv, passive_session (int xserver, int fd, kx_context *kc)
des_key_schedule schedule)
{ {
if (replace_cookie (xserver, fd, XauFileName(), 1)) if (replace_cookie (xserver, fd, XauFileName(), 1))
return 1; return 1;
else else
return copy_encrypted (xserver, fd, iv, schedule); return copy_encrypted (kc, xserver, fd);
} }
static int static int
active_session (int xserver, int fd, des_cblock *iv, active_session (int xserver, int fd, kx_context *kc)
des_key_schedule schedule)
{ {
if (verify_and_remove_cookies (xserver, fd, 1)) if (verify_and_remove_cookies (xserver, fd, 1))
return 1; return 1;
else else
return copy_encrypted (xserver, fd, iv, schedule); return copy_encrypted (kc, xserver, fd);
} }
static void static void
@@ -208,24 +196,20 @@ status_output (int debugp)
*/ */
static int static int
doit_passive (char *host, char *user, int debugp, int keepalivep, doit_passive (kx_context *kc)
int port)
{ {
des_key_schedule schedule;
des_cblock key;
int otherside; int otherside;
struct sockaddr_in me, him;
u_char msg[1024], *p; u_char msg[1024], *p;
int len; int len;
void *ret;
u_int32_t tmp; u_int32_t tmp;
char *host = kc->host;
otherside = connect_host (kc);
otherside = connect_host (host, user, &key, schedule, port,
&me, &him);
if (otherside < 0) if (otherside < 0)
return 1; return 1;
#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
if (keepalivep) { if (kc->keepalive_flag) {
int one = 1; int one = 1;
setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
@@ -235,22 +219,20 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
p = msg; p = msg;
*p++ = INIT; *p++ = INIT;
len = strlen(user); len = strlen(kc->user);
p += krb_put_int (len, p, sizeof(msg) - 1, 4); p += KRB_PUT_INT (len, p, sizeof(msg) - 1, 4);
memcpy(p, user, len); memcpy(p, kc->user, len);
p += len; p += len;
*p++ = PASSIVE | (keepalivep ? KEEP_ALIVE : 0); *p++ = PASSIVE | (kc->keepalive_flag ? KEEP_ALIVE : 0);
if (write_encrypted (otherside, msg, p - msg, schedule, if (kx_write (kc, otherside, msg, p - msg) != p - msg)
&key, &me, &him) < 0)
err (1, "write to %s", host); err (1, "write to %s", host);
len = read_encrypted (otherside, msg, sizeof(msg), &ret, len = kx_read (kc, otherside, msg, sizeof(msg));
schedule, &key, &him, &me);
if (len <= 0) if (len <= 0)
errx (1, errx (1,
"error reading initial message from %s: " "error reading initial message from %s: "
"this probably means it's using an old version.", "this probably means it's using an old version.",
host); host);
p = (u_char *)ret; p = (u_char *)msg;
if (*p == ERROR) { if (*p == ERROR) {
p++; p++;
p += krb_get_int (p, &tmp, 4, 0); p += krb_get_int (p, &tmp, 4, 0);
@@ -269,18 +251,17 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
xauthfile[tmp] = '\0'; xauthfile[tmp] = '\0';
p += tmp; p += tmp;
status_output (debugp); status_output (kc->debug_flag);
for (;;) { for (;;) {
pid_t child; pid_t child;
len = read_encrypted (otherside, msg, sizeof(msg), &ret, len = kx_read (kc, otherside, msg, sizeof(msg));
schedule, &key, &him, &me);
if (len < 0) if (len < 0)
err (1, "read from %s", host); err (1, "read from %s", host);
else if (len == 0) else if (len == 0)
return 0; return 0;
p = (u_char *)ret; p = (u_char *)msg;
if (*p == ERROR) { if (*p == ERROR) {
p++; p++;
p += krb_get_int (p, &tmp, 4, 0); p += krb_get_int (p, &tmp, 4, 0);
@@ -302,7 +283,7 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
int fd; int fd;
int xserver; int xserver;
addr = him; addr = kc->thataddr;
close (otherside); close (otherside);
addr.sin_port = htons(tmp); addr.sin_port = htons(tmp);
@@ -318,7 +299,7 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
} }
#endif #endif
#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
if (keepalivep) { if (kc->keepalive_flag) {
int one = 1; int one = 1;
setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
@@ -343,7 +324,7 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
if (xserver < 0) if (xserver < 0)
return 1; return 1;
} }
return passive_session (xserver, fd, &key, schedule); return passive_session (xserver, fd, kc);
} else { } else {
} }
} }
@@ -354,31 +335,26 @@ doit_passive (char *host, char *user, int debugp, int keepalivep,
*/ */
static int static int
doit_active (char *host, char *user, doit_active (kx_context *kc)
int debugpp, int keepalivep, int tcpp, int port)
{ {
des_key_schedule schedule;
des_cblock key;
int otherside; int otherside;
int nsockets; int nsockets;
struct x_socket *sockets; struct x_socket *sockets;
struct sockaddr_in me, him;
u_char msg[1024], *p; u_char msg[1024], *p;
int len = strlen(user); int len = strlen(kc->user);
void *ret;
int tmp, tmp2; int tmp, tmp2;
char *s; char *s;
int i; int i;
size_t rem; size_t rem;
u_int32_t other_port; u_int32_t other_port;
int error; int error;
char *host = kc->host;
otherside = connect_host (host, user, &key, schedule, port, otherside = connect_host (kc);
&me, &him);
if (otherside < 0) if (otherside < 0)
return 1; return 1;
#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
if (keepalivep) { if (kc->keepalive_flag) {
int one = 1; int one = 1;
setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
@@ -389,23 +365,23 @@ doit_active (char *host, char *user,
rem = sizeof(msg); rem = sizeof(msg);
*p++ = INIT; *p++ = INIT;
--rem; --rem;
len = strlen(user); len = strlen(kc->user);
tmp = krb_put_int (len, p, rem, 4); tmp = KRB_PUT_INT (len, p, rem, 4);
if (tmp < 0) if (tmp < 0)
return 1; return 1;
p += tmp; p += tmp;
rem -= tmp; rem -= tmp;
memcpy(p, user, len); memcpy(p, kc->user, len);
p += len; p += len;
rem -= len; rem -= len;
*p++ = (keepalivep ? KEEP_ALIVE : 0); *p++ = (kc->keepalive_flag ? KEEP_ALIVE : 0);
--rem; --rem;
s = getenv("DISPLAY"); s = getenv("DISPLAY");
if (s == NULL || (s = strchr(s, ':')) == NULL) if (s == NULL || (s = strchr(s, ':')) == NULL)
s = ":0"; s = ":0";
len = strlen (s); len = strlen (s);
tmp = krb_put_int (len, p, rem, 4); tmp = KRB_PUT_INT (len, p, rem, 4);
if (tmp < 0) if (tmp < 0)
return 1; return 1;
rem -= tmp; rem -= tmp;
@@ -418,7 +394,7 @@ doit_active (char *host, char *user,
if (s == NULL) if (s == NULL)
s = ""; s = "";
len = strlen (s); len = strlen (s);
tmp = krb_put_int (len, p, rem, 4); tmp = KRB_PUT_INT (len, p, rem, 4);
if (tmp < 0) if (tmp < 0)
return 1; return 1;
p += len; p += len;
@@ -427,15 +403,13 @@ doit_active (char *host, char *user,
p += len; p += len;
rem -= len; rem -= len;
if (write_encrypted (otherside, msg, p - msg, schedule, if (kx_write (kc, otherside, msg, p - msg) != p - msg)
&key, &me, &him) < 0)
err (1, "write to %s", host); err (1, "write to %s", host);
len = read_encrypted (otherside, msg, sizeof(msg), &ret, len = kx_read (kc, otherside, msg, sizeof(msg));
schedule, &key, &him, &me);
if (len < 0) if (len < 0)
err (1, "read from %s", host); err (1, "read from %s", host);
p = (u_char *)ret; p = (u_char *)msg;
if (*p == ERROR) { if (*p == ERROR) {
u_int32_t u32; u_int32_t u32;
@@ -447,11 +421,11 @@ doit_active (char *host, char *user,
} else } else
p++; p++;
tmp2 = get_xsockets (&nsockets, &sockets, tcpp); tmp2 = get_xsockets (&nsockets, &sockets, kc->tcp_flag);
if (tmp2 < 0) if (tmp2 < 0)
return 1; return 1;
display_num = tmp2; display_num = tmp2;
if (tcpp) if (kc->tcp_flag)
snprintf (display, display_size, "localhost:%u", display_num); snprintf (display, display_size, "localhost:%u", display_num);
else else
snprintf (display, display_size, ":%u", display_num); snprintf (display, display_size, ":%u", display_num);
@@ -461,7 +435,7 @@ doit_active (char *host, char *user,
warnx ("failed creating cookie file: %s", strerror(error)); warnx ("failed creating cookie file: %s", strerror(error));
return 1; return 1;
} }
status_output (debugpp); status_output (kc->debug_flag);
for (;;) { for (;;) {
fd_set fdset; fd_set fdset;
pid_t child; pid_t child;
@@ -488,14 +462,12 @@ doit_active (char *host, char *user,
p = msg; p = msg;
*p++ = NEW_CONN; *p++ = NEW_CONN;
if (write_encrypted (otherside, msg, p - msg, schedule, if (kx_write (kc, otherside, msg, p - msg) != p - msg)
&key, &me, &him) < 0)
err (1, "write to %s", host); err (1, "write to %s", host);
len = read_encrypted (otherside, msg, sizeof(msg), &ret, len = kx_read (kc, otherside, msg, sizeof(msg));
schedule, &key, &him, &me);
if (len < 0) if (len < 0)
err (1, "read from %s", host); err (1, "read from %s", host);
p = (u_char *)ret; p = (u_char *)msg;
if (*p == ERROR) { if (*p == ERROR) {
u_int32_t val; u_int32_t val;
@@ -521,7 +493,7 @@ doit_active (char *host, char *user,
for (i = 0; i < nsockets; ++i) for (i = 0; i < nsockets; ++i)
close (sockets[i].fd); close (sockets[i].fd);
addr = him; addr = kc->thataddr;
close (otherside); close (otherside);
addr.sin_port = htons(other_port); addr.sin_port = htons(other_port);
@@ -537,7 +509,7 @@ doit_active (char *host, char *user,
} }
#endif #endif
#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
if (keepalivep) { if (kc->keepalive_flag) {
int one = 1; int one = 1;
setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (void *)&one,
@@ -548,7 +520,7 @@ doit_active (char *host, char *user,
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) < 0) if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
err(1, "connect"); err(1, "connect");
return active_session (fd, s, &key, schedule); return active_session (fd, s, kc);
} else { } else {
close (fd); close (fd);
} }
@@ -573,79 +545,212 @@ check_for_passive (const char *disp)
|| strncmp(disp, local_hostname, strlen(local_hostname)) == 0); || strncmp(disp, local_hostname, strlen(local_hostname)) == 0);
} }
static void static int
usage(void) doit (kx_context *kc, int passive_flag)
{ {
fprintf(stderr, "Usage: %s [-p port] [-d] [-D] [-t] [-l remoteuser] host\n", signal (SIGCHLD, childhandler);
__progname); signal (SIGUSR1, usr1handler);
exit (1); signal (SIGUSR2, usr2handler);
if (passive_flag)
return doit_passive (kc);
else
return doit_active (kc);
}
#ifdef KRB4
static int
doit_v4 (char *host, int port, char *user,
int passive_flag, int debug_flag, int keepalive_flag, int tcp_flag)
{
int ret;
kx_context context;
krb4_make_context (&context);
context_set (&context,
host, user, port, debug_flag, keepalive_flag, tcp_flag);
ret = doit (&context, passive_flag);
context_destroy (&context);
return ret;
}
#endif /* KRB4 */
#ifdef KRB5
static int
doit_v5 (char *host, int port, char *user,
int passive_flag, int debug_flag, int keepalive_flag, int tcp_flag)
{
int ret;
kx_context context;
krb5_make_context (&context);
context_set (&context,
host, user, port, debug_flag, keepalive_flag, tcp_flag);
ret = doit (&context, passive_flag);
context_destroy (&context);
return ret;
}
#endif
/*
*
*/
#ifdef KRB4
static int use_v4 = 0;
static int krb_debug_flag = 0;
#endif
#ifdef KRB5
static int use_v5 = 0;
static int forward_flag = 0;
static int forwardable_flag = 0;
#endif
static char *port_str = NULL;
static char *user = NULL;
static int tcp_flag = 0;
static int passive_flag = 0;
static int keepalive_flag = 1;
static int debug_flag = 0;
static int version_flag = 0;
static int help_flag = 0;
struct getargs args[] = {
#ifdef KRB4
{ "krb4", '4', arg_flag, &use_v4, "Use Kerberos V4",
NULL },
{ "krb4-debug", 'D', arg_flag, &krb_debug_flag,
"enable krb4 debugging" },
#endif
#ifdef KRB5
{ "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5",
NULL },
{ "forward", 'f', arg_flag, &forward_flag, "Forward credentials",
NULL },
{ "forwardable", 'F', arg_flag, &forwardable_flag,
"Forward forwardable credentials", NULL },
#endif
{ "port", 'p', arg_string, &port_str, "Use this port",
"number-of-service" },
{ "user", 'l', arg_string, &user, "Run as this user",
NULL },
{ "tcp", 't', arg_flag, &tcp_flag,
"Use a TCP connection for X11" },
{ "passive", 'P', arg_flag, &passive_flag,
"Force a passive connection" },
{ "keepalive", 'k', arg_negative_flag, &keepalive_flag,
"disable keep-alives" },
{ "debug", 'd', arg_flag, &debug_flag,
"Enable debug information" },
{ "version", 0, arg_flag, &version_flag, "Print version",
NULL },
{ "help", 0, arg_flag, &help_flag, NULL,
NULL }
};
static void
usage(int ret)
{
arg_printusage (args,
sizeof(args) / sizeof(args[0]),
NULL,
"host");
exit (ret);
} }
/* /*
* kx - forward x connection over a kerberos-encrypted channel. * kx - forward x connection over a kerberos-encrypted channel.
*
*/ */
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int force_passive = 0;
int keepalivep = 1;
char *user = NULL;
int debugp = 0, tcpp = 0;
int c;
int port = 0; int port = 0;
int optind = 0;
int ret = 1;
char *host = NULL;
set_progname (argv[0]); set_progname (argv[0]);
while((c = getopt(argc, argv, "ktdDl:p:P")) != EOF) {
switch(c) { if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
case 'd' : &optind))
debugp = 1; usage (1);
break;
case 'D': if (help_flag)
krb_enable_debug(); usage (0);
break;
case 'k': if (version_flag) {
keepalivep = 0; print_version (NULL);
break; return 0;
case 't' : }
tcpp = 1;
break; if (optind != argc - 1)
case 'l' : usage (1);
user = optarg;
break; if (forwardable_flag)
case 'p' : forward_flag = 1;
port = htons(atoi (optarg));
break; host = argv[optind];
case 'P' :
force_passive = 1; if (port_str) {
break; struct servent *s = roken_getservbyname (port_str, "tcp");
case '?':
default: if (s)
usage(); port = s->s_port;
else {
char *ptr;
port = strtol (port_str, &ptr, 10);
if (port == 0 && ptr == port_str)
errx (1, "Bad port `%s'", port_str);
port = htons(port);
} }
} }
argc -= optind;
argv += optind;
if (argc != 1)
usage ();
if (user == NULL) { if (user == NULL) {
struct passwd *p = k_getpwuid (getuid ()); struct passwd *pwd = getpwuid (getuid ());
if (p == NULL)
errx(1, "Who are you?"); if (pwd == NULL)
user = strdup (p->pw_name); errx (1, "who are you?");
if (user == NULL) user = pwd->pw_name;
errx (1, "strdup: out of memory");
} }
if (!passive_flag)
passive_flag = check_for_passive (getenv("DISPLAY"));
#ifdef KRB4
if (krb_debug_flag)
krb_enable_debug ();
#endif
#if defined(KRB5)
#if defined(KRB4)
if (use_v4 == 0 && use_v5 == 0)
use_v5 = 1;
#else
use_v5 = 1;
#endif /* KRB4 */
#elif defined(KRB4)
use_v4 = 1;
#endif
#ifdef KRB5
if (ret && use_v5) {
if (port == 0)
port = krb5_getportbyname(NULL, "kx", "tcp", htons(KX_PORT));
ret = doit_v5 (host, port, user,
passive_flag, debug_flag, keepalive_flag, tcp_flag);
}
#endif
#ifdef KRB4
if (ret && use_v4) {
if (port == 0) if (port == 0)
port = k_getportbyname("kx", "tcp", htons(KX_PORT)); port = k_getportbyname("kx", "tcp", htons(KX_PORT));
signal (SIGCHLD, childhandler); ret = doit_v4 (host, port, user,
signal (SIGUSR1, usr1handler); passive_flag, debug_flag, keepalive_flag, tcp_flag);
signal (SIGUSR2, usr2handler); }
if (force_passive || check_for_passive(getenv("DISPLAY"))) #endif
return doit_passive (argv[0], user, debugp, keepalivep, port); return ret;
else
return doit_active (argv[0], user, debugp, keepalivep, tcpp, port);
} }

View File

@@ -57,20 +57,8 @@ childhandler (int sig)
SIGRETURN(0); SIGRETURN(0);
} }
static void void
fatal(int, des_cblock *, des_key_schedule, fatal (kx_context *kc, int fd, char *format, ...)
struct sockaddr_in *, struct sockaddr_in *,
char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 6, 7)))
#endif
;
static void
fatal (int fd, des_cblock *key, des_key_schedule schedule,
struct sockaddr_in *thisaddr,
struct sockaddr_in *thataddr,
char *format, ...)
{ {
u_char msg[1024]; u_char msg[1024];
u_char *p; u_char *p;
@@ -83,9 +71,9 @@ fatal (int fd, des_cblock *key, des_key_schedule schedule,
vsnprintf (p + 4, sizeof(msg) - 5, format, args); vsnprintf (p + 4, sizeof(msg) - 5, format, args);
syslog (LOG_ERR, p + 4); syslog (LOG_ERR, p + 4);
len = strlen (p + 4); len = strlen (p + 4);
p += krb_put_int (len, p, 4, 4); p += KRB_PUT_INT (len, p, 4, 4);
p += len; p += len;
write_encrypted (fd, msg, p - msg, schedule, key, thisaddr, thataddr); kx_write (kc, fd, msg, p - msg);
va_end(args); va_end(args);
exit (1); exit (1);
} }
@@ -105,80 +93,68 @@ cleanup(int nsockets, struct x_socket *sockets)
} }
} }
static int /*
recv_conn (int sock, des_cblock *key, des_key_schedule schedule, *
struct sockaddr_in *thisaddr, */
struct sockaddr_in *thataddr,
int *dispnr,
int *nsockets,
struct x_socket **sockets,
int tcpp)
{
int status;
KTEXT_ST ticket;
AUTH_DAT auth;
char user[ANAME_SZ];
char instance[INST_SZ];
int addrlen;
char version[KRB_SENDAUTH_VLEN + 1];
struct passwd *passwd;
char remotehost[MaxHostNameLen];
void *ret;
int len;
u_char msg[1024], *p;
u_int32_t tmp32;
int tmp;
int flags;
addrlen = sizeof(*thisaddr); static int
if (getsockname (sock, (struct sockaddr *)thisaddr, &addrlen) < 0 || recv_conn (int sock, kx_context *kc,
addrlen != sizeof(*thisaddr)) { int *dispnr, int *nsockets, struct x_socket **sockets,
int tcp_flag)
{
u_char msg[1024], *p;
char user[256];
int addrlen;
struct passwd *passwd;
struct sockaddr_in thisaddr, thataddr;
char remotehost[MaxHostNameLen];
int ret = 1;
int flags;
int len;
u_int32_t tmp32;
addrlen = sizeof(thisaddr);
if (getsockname (sock, (struct sockaddr *)&thisaddr, &addrlen) < 0 ||
addrlen != sizeof(thisaddr)) {
syslog (LOG_ERR, "getsockname: %m"); syslog (LOG_ERR, "getsockname: %m");
exit (1); exit (1);
} }
addrlen = sizeof(*thataddr); addrlen = sizeof(thataddr);
if (getpeername (sock, (struct sockaddr *)thataddr, &addrlen) < 0 || if (getpeername (sock, (struct sockaddr *)&thataddr, &addrlen) < 0 ||
addrlen != sizeof(*thataddr)) { addrlen != sizeof(thataddr)) {
syslog (LOG_ERR, "getpeername: %m"); syslog (LOG_ERR, "getpeername: %m");
exit (1); exit (1);
} }
inaddr2str (thataddr->sin_addr, remotehost, sizeof(remotehost)); kc->thisaddr = thisaddr;
kc->thataddr = thataddr;
k_getsockinst (sock, instance, sizeof(instance)); inaddr2str (thataddr.sin_addr, remotehost, sizeof(remotehost));
status = krb_recvauth (KOPT_DO_MUTUAL, sock, &ticket, "rcmd", instance,
thataddr, thisaddr, &auth, "", schedule,
version);
if (status != KSUCCESS) {
syslog (LOG_ERR, "krb_recvauth: %s",
krb_get_err_text(status));
exit(1);
}
if( strncmp(version, KX_VERSION, KRB_SENDAUTH_VLEN) != 0) {
/* Try to be nice to old kx's */
if (strncmp (version, KX_OLD_VERSION, KRB_SENDAUTH_VLEN) == 0) {
char *old_errmsg = "\001Old version of kx. Please upgrade.";
syslog (LOG_ERR, "Old version client (%s)", version); if (net_read (sock, msg, 4) != 4) {
syslog (LOG_ERR, "read: %m");
krb_net_read (sock, user, sizeof(user));
krb_net_write (sock, old_errmsg, strlen(old_errmsg) + 1);
exit (1); exit (1);
} }
fatal(sock, key, schedule, thisaddr, thataddr, #ifdef KRB5
"Bad version %s", version); if (ret && recv_v5_auth (kc, sock, msg) == 0)
ret = 0;
#endif
#ifdef KRB4
if (ret && recv_v4_auth (kc, sock, msg) == 0)
ret = 0;
#endif
if (ret) {
syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x");
return 1;
} }
memcpy(key, &auth.session, sizeof(des_cblock));
len = read_encrypted (sock, msg, sizeof(msg), &ret, len = kx_read (kc, sock, msg, sizeof(msg));
schedule, key, thataddr, thisaddr);
if (len < 0) if (len < 0)
return 1; return 1;
p = (u_char *)ret; p = (u_char *)msg;
if (*p != INIT) if (*p != INIT)
fatal(sock, key, schedule, thisaddr, thataddr, fatal(kc, sock, "Bad message");
"Bad message");
p++; p++;
p += krb_get_int (p, &tmp32, 4, 0); p += krb_get_int (p, &tmp32, 4, 0);
len = min(sizeof(user), tmp32); len = min(sizeof(user), tmp32);
@@ -188,25 +164,21 @@ recv_conn (int sock, des_cblock *key, des_key_schedule schedule,
passwd = k_getpwnam (user); passwd = k_getpwnam (user);
if (passwd == NULL) if (passwd == NULL)
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "cannot find uid for %s", user);
"Cannot find uid");
if (kuserok(&auth, user) != 0) if (context_userok (kc, user) != 0)
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "%s not allowed to login as %s",
"%s is not allowed to login as %s", kc->user, user);
krb_unparse_name_long (auth.pname,
auth.pinst,
auth.prealm),
user);
flags = *p++; flags = *p++;
if (flags & PASSIVE) { if (flags & PASSIVE) {
pid_t pid; pid_t pid;
int tmp;
tmp = get_xsockets (nsockets, sockets, tcpp); tmp = get_xsockets (nsockets, sockets, tcp_flag);
if (tmp < 0) { if (tmp < 0) {
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "Cannot create X socket(s): %s",
"Cannot create X socket(s): %s",
strerror(errno)); strerror(errno));
} }
*dispnr = tmp; *dispnr = tmp;
@@ -214,16 +186,14 @@ recv_conn (int sock, des_cblock *key, des_key_schedule schedule,
if (chown_xsockets (*nsockets, *sockets, if (chown_xsockets (*nsockets, *sockets,
passwd->pw_uid, passwd->pw_gid)) { passwd->pw_uid, passwd->pw_gid)) {
cleanup (*nsockets, *sockets); cleanup (*nsockets, *sockets);
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "Cannot chown sockets: %s",
"Cannot chown sockets: %s",
strerror(errno)); strerror(errno));
} }
pid = fork(); pid = fork();
if (pid == -1) { if (pid == -1) {
cleanup (*nsockets, *sockets); cleanup (*nsockets, *sockets);
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "fork: %s", strerror(errno));
"fork: %s", strerror(errno));
} else if (pid != 0) { } else if (pid != 0) {
int status; int status;
@@ -239,14 +209,12 @@ recv_conn (int sock, des_cblock *key, des_key_schedule schedule,
if (setgid (passwd->pw_gid) || if (setgid (passwd->pw_gid) ||
initgroups(passwd->pw_name, passwd->pw_gid) || initgroups(passwd->pw_name, passwd->pw_gid) ||
setuid(passwd->pw_uid)) { setuid(passwd->pw_uid)) {
fatal (sock, key, schedule, thisaddr, thataddr, fatal (kc, sock, "cannot set uid");
"Cannot set uid");
} }
syslog (LOG_INFO, "from %s(%s): %s -> %s", syslog (LOG_INFO, "from %s(%s): %s -> %s",
remotehost, remotehost,
inet_ntoa(thataddr->sin_addr), inet_ntoa(thataddr.sin_addr),
krb_unparse_name_long (auth.pname, auth.pinst, auth.prealm), kc->user);
user);
umask(077); umask(077);
if (!(flags & PASSIVE)) { if (!(flags & PASSIVE)) {
p += krb_get_int (p, &tmp32, 4, 0); p += krb_get_int (p, &tmp32, 4, 0);
@@ -276,35 +244,32 @@ recv_conn (int sock, des_cblock *key, des_key_schedule schedule,
*/ */
static int static int
passive_session (int fd, int sock, int cookiesp, des_cblock *key, passive_session (kx_context *kc, int fd, int sock, int cookiesp)
des_key_schedule schedule)
{ {
if (verify_and_remove_cookies (fd, sock, cookiesp)) if (verify_and_remove_cookies (fd, sock, cookiesp))
return 1; return 1;
else else
return copy_encrypted (fd, sock, key, schedule); return copy_encrypted (kc, fd, sock);
} }
static int static int
active_session (int fd, int sock, int cookiesp, des_cblock *key, active_session (kx_context *kc, int fd, int sock, int cookiesp)
des_key_schedule schedule)
{ {
fd = connect_local_xsocket(0); fd = connect_local_xsocket(0);
if (replace_cookie (fd, sock, xauthfile, cookiesp)) if (replace_cookie (fd, sock, xauthfile, cookiesp))
return 1; return 1;
else else
return copy_encrypted (fd, sock, key, schedule); return copy_encrypted (kc, fd, sock);
} }
static int static int
doit_conn (int fd, int meta_sock, int flags, int cookiesp, doit_conn (kx_context *kc,
des_cblock *key, des_key_schedule schedule, int fd, int meta_sock, int flags, int cookiesp)
struct sockaddr_in *thisaddr,
struct sockaddr_in *thataddr)
{ {
int sock, sock2; int sock, sock2;
struct sockaddr_in addr; struct sockaddr_in addr;
struct sockaddr_in thisaddr;
int addrlen; int addrlen;
u_char msg[1024], *p; u_char msg[1024], *p;
@@ -334,8 +299,7 @@ doit_conn (int fd, int meta_sock, int flags, int cookiesp,
return 1; return 1;
} }
addrlen = sizeof(addr); addrlen = sizeof(addr);
if (getsockname (sock, (struct sockaddr *)&addr, if (getsockname (sock, (struct sockaddr *)&addr, &addrlen) < 0) {
&addrlen) < 0) {
syslog (LOG_ERR, "getsockname: %m"); syslog (LOG_ERR, "getsockname: %m");
return 1; return 1;
} }
@@ -345,15 +309,15 @@ doit_conn (int fd, int meta_sock, int flags, int cookiesp,
} }
p = msg; p = msg;
*p++ = NEW_CONN; *p++ = NEW_CONN;
p += krb_put_int (ntohs(addr.sin_port), p, 4, 4); p += KRB_PUT_INT (ntohs(addr.sin_port), p, 4, 4);
if (write_encrypted (meta_sock, msg, p - msg, schedule, key, if (kx_write (kc, meta_sock, msg, p - msg) < 0) {
thisaddr, thataddr) < 0) {
syslog (LOG_ERR, "write: %m"); syslog (LOG_ERR, "write: %m");
return 1; return 1;
} }
sock2 = accept (sock, (struct sockaddr *)thisaddr, &addrlen); addrlen = sizeof(thisaddr);
sock2 = accept (sock, (struct sockaddr *)&thisaddr, &addrlen);
if (sock2 < 0) { if (sock2 < 0) {
syslog (LOG_ERR, "accept: %m"); syslog (LOG_ERR, "accept: %m");
return 1; return 1;
@@ -362,9 +326,9 @@ doit_conn (int fd, int meta_sock, int flags, int cookiesp,
close (meta_sock); close (meta_sock);
if (flags & PASSIVE) if (flags & PASSIVE)
return passive_session (fd, sock2, cookiesp, key, schedule); return passive_session (kc, fd, sock2, cookiesp);
else else
return active_session (fd, sock2, cookiesp, key, schedule); return active_session (kc, fd, sock2, cookiesp);
} }
/* /*
@@ -372,18 +336,14 @@ doit_conn (int fd, int meta_sock, int flags, int cookiesp,
*/ */
static void static void
check_user_console (int fd, des_cblock *key, des_key_schedule schedule, check_user_console (kx_context *kc, int fd)
struct sockaddr_in *thisaddr,
struct sockaddr_in *thataddr)
{ {
struct stat sb; struct stat sb;
if (stat ("/dev/console", &sb) < 0) if (stat ("/dev/console", &sb) < 0)
fatal (fd, key, schedule, thisaddr, thataddr, fatal (kc, fd, "Cannot stat /dev/console: %s", strerror(errno));
"Cannot stat /dev/console");
if (getuid() != sb.st_uid) if (getuid() != sb.st_uid)
fatal (fd, key, schedule, thisaddr, thataddr, fatal (kc, fd, "Permission denied");
"Permission denied");
} }
/* /*
@@ -391,10 +351,13 @@ check_user_console (int fd, des_cblock *key, des_key_schedule schedule,
*/ */
static int static int
doit_passive (int sock, des_cblock *key, des_key_schedule schedule, doit_passive (kx_context *kc,
struct sockaddr_in *me, struct sockaddr_in *him, int flags, int sock,
int displaynr, int nsockets, struct x_socket *sockets, int flags,
int tcpp) int dispnr,
int nsockets,
struct x_socket *sockets,
int tcp_flag)
{ {
int tmp; int tmp;
int len; int len;
@@ -402,8 +365,8 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
u_char msg[1024], *p; u_char msg[1024], *p;
int error; int error;
display_num = displaynr; display_num = dispnr;
if (tcpp) if (tcp_flag)
snprintf (display, display_size, "localhost:%u", display_num); snprintf (display, display_size, "localhost:%u", display_num);
else else
snprintf (display, display_size, ":%u", display_num); snprintf (display, display_size, ":%u", display_num);
@@ -411,9 +374,7 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
cookie, cookie_len); cookie, cookie_len);
if (error) { if (error) {
cleanup(nsockets, sockets); cleanup(nsockets, sockets);
fatal (sock, key, schedule, me, him, fatal (kc, sock, "Cookie-creation failed: %s", strerror(error));
"Cookie-creation failed with: %s",
strerror(error));
return 1; return 1;
} }
@@ -423,7 +384,7 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
--rem; --rem;
len = strlen (display); len = strlen (display);
tmp = krb_put_int (len, p, rem, 4); tmp = KRB_PUT_INT (len, p, rem, 4);
if (tmp < 0 || rem < len + 4) { if (tmp < 0 || rem < len + 4) {
syslog (LOG_ERR, "doit: buffer too small"); syslog (LOG_ERR, "doit: buffer too small");
cleanup(nsockets, sockets); cleanup(nsockets, sockets);
@@ -437,7 +398,7 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
rem -= len; rem -= len;
len = strlen (xauthfile); len = strlen (xauthfile);
tmp = krb_put_int (len, p, rem, 4); tmp = KRB_PUT_INT (len, p, rem, 4);
if (tmp < 0 || rem < len + 4) { if (tmp < 0 || rem < len + 4) {
syslog (LOG_ERR, "doit: buffer too small"); syslog (LOG_ERR, "doit: buffer too small");
cleanup(nsockets, sockets); cleanup(nsockets, sockets);
@@ -450,8 +411,7 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
p += len; p += len;
rem -= len; rem -= len;
if(write_encrypted (sock, msg, p - msg, schedule, key, if(kx_write (kc, sock, msg, p - msg) < 0) {
me, him) < 0) {
syslog (LOG_ERR, "write: %m"); syslog (LOG_ERR, "write: %m");
cleanup(nsockets, sockets); cleanup(nsockets, sockets);
return 1; return 1;
@@ -550,8 +510,7 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
} else if (child == 0) { } else if (child == 0) {
for (i = 0; i < nsockets; ++i) for (i = 0; i < nsockets; ++i)
close (sockets[i].fd); close (sockets[i].fd);
return doit_conn (fd, sock, flags, cookiesp, return doit_conn (kc, fd, sock, flags, cookiesp);
key, schedule, me, him);
} else { } else {
close (fd); close (fd);
} }
@@ -563,35 +522,32 @@ doit_passive (int sock, des_cblock *key, des_key_schedule schedule,
*/ */
static int static int
doit_active (int sock, des_cblock *key, des_key_schedule schedule, doit_active (kx_context *kc,
struct sockaddr_in *me, struct sockaddr_in *him, int sock,
int flags, int tcpp) int flags,
int tcp_flag)
{ {
u_char msg[1024], *p; u_char msg[1024], *p;
check_user_console (sock, key, schedule, me, him); check_user_console (kc, sock);
p = msg; p = msg;
*p++ = ACK; *p++ = ACK;
if(write_encrypted (sock, msg, p - msg, schedule, key, if(kx_write (kc, sock, msg, p - msg) < 0) {
me, him) < 0) {
syslog (LOG_ERR, "write: %m"); syslog (LOG_ERR, "write: %m");
return 1; return 1;
} }
for (;;) { for (;;) {
pid_t child; pid_t child;
int len; int len;
void *ret;
len = read_encrypted (sock, msg, sizeof(msg), &ret, len = kx_read (kc, sock, msg, sizeof(msg));
schedule, key,
him, me);
if (len < 0) { if (len < 0) {
syslog (LOG_ERR, "read: %m"); syslog (LOG_ERR, "read: %m");
return 1; return 1;
} }
p = (u_char *)ret; p = (u_char *)msg;
if (*p != NEW_CONN) { if (*p != NEW_CONN) {
syslog (LOG_ERR, "bad_message: %d", *p); syslog (LOG_ERR, "bad_message: %d", *p);
return 1; return 1;
@@ -602,8 +558,7 @@ doit_active (int sock, des_cblock *key, des_key_schedule schedule,
syslog (LOG_ERR, "fork: %m"); syslog (LOG_ERR, "fork: %m");
return 1; return 1;
} else if (child == 0) { } else if (child == 0) {
return doit_conn (sock, sock, flags, 1, return doit_conn (kc, sock, sock, flags, 1);
key, schedule, me, him);
} else { } else {
} }
} }
@@ -614,31 +569,49 @@ doit_active (int sock, des_cblock *key, des_key_schedule schedule,
*/ */
static int static int
doit(int sock, int tcpp) doit(int sock, int tcp_flag)
{ {
des_key_schedule schedule; int ret;
des_cblock key; kx_context context;
struct sockaddr_in me, him;
int flags;
struct x_socket *sockets;
int nsockets;
int dispnr; int dispnr;
int nsockets;
struct x_socket *sockets;
int flags;
flags = recv_conn (sock, &key, schedule, &me, &him, flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag);
&dispnr, &nsockets, &sockets, tcpp);
if (flags & PASSIVE) if (flags & PASSIVE)
return doit_passive (sock, &key, schedule, &me, &him, flags, ret = doit_passive (&context, sock, flags, dispnr,
dispnr, nsockets, sockets, tcpp); nsockets, sockets, tcp_flag);
else else
return doit_active (sock, &key, schedule, &me, &him, flags, tcpp); ret = doit_active (&context, sock, flags, tcp_flag);
context_destroy (&context);
return ret;
} }
static char *port_str = NULL;
static int inetd_flag = 0;
static int tcp_flag = 0;
static int version_flag = 0;
static int help_flag = 0;
struct getargs args[] = {
{ "inetd", 'i', arg_negative_flag, &inetd_flag,
"Not started from inetd" },
{ "port", 'p', arg_string, &port_str, "Use this port",
"port" },
{ "version", 0, arg_flag, &version_flag },
{ "help", 0, arg_flag, &help_flag }
};
static void static void
usage (void) usage(int ret)
{ {
fprintf (stderr, "Usage: %s [-i] [-t] [-p port]\n", __progname); arg_printusage (args,
exit (1); sizeof(args) / sizeof(args[0]),
NULL,
"host");
exit (ret);
} }
/* /*
@@ -648,34 +621,50 @@ usage (void)
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
int c; int port;
int no_inetd = 0; int optind = 0;
int tcpp = 0;
int port = 0;
set_progname (argv[0]); set_progname (argv[0]);
roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON);
while( (c = getopt (argc, argv, "itp:")) != EOF) { if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
switch (c) { &optind))
case 'i': usage (1);
no_inetd = 1;
break; if (help_flag)
case 't': usage (0);
tcpp = 1;
break; if (version_flag) {
case 'p': print_version (NULL);
port = htons(atoi (optarg)); return 0;
break;
case '?':
default:
usage ();
}
} }
if (no_inetd) if(port_str) {
mini_inetd (port ? port : k_getportbyname("kx", "tcp", struct servent *s = roken_getservbyname (port_str, "tcp");
htons(KX_PORT)));
roken_openlog(__progname, LOG_PID|LOG_CONS, LOG_DAEMON); if (s)
port = s->s_port;
else {
char *ptr;
port = strtol (port_str, &ptr, 10);
if (port == 0 && ptr == port_str)
errx (1, "bad port `%s'", port_str);
port = htons(port);
}
} else {
#if defined(KRB5)
port = krb5_getportbyname(NULL, "kx", "tcp", htons(KX_PORT));
#elif defined(KRB4)
port = k_getportbyname ("kx", "tcp", htons(KX_PORT));
#else
#error define KRB4 or KRB5
#endif
}
if (!inetd_flag)
mini_inetd (port);
signal (SIGCHLD, childhandler); signal (SIGCHLD, childhandler);
return doit(STDIN_FILENO, tcpp); return doit(STDIN_FILENO, tcp_flag);
} }