|
Michel Lind |
1c324b |
--- a/session.c
|
|
|
d1c05f |
+++ b/session.c
|
|
|
d1c05f |
@@ -98,6 +98,7 @@
|
|
|
d1c05f |
#include "atomicio.h"
|
|
|
d1c05f |
#include "slog.h"
|
|
|
d1c05f |
|
|
|
d1c05f |
+#define SSH_MAX_PUBKEY_BYTES 16384
|
|
|
d1c05f |
|
|
|
d1c05f |
#if defined(KRB5) && defined(USE_AFS)
|
|
|
d1c05f |
#include <kafs.h>
|
|
|
f94360 |
@@ -1054,11 +1055,18 @@ copy_environment(char **source, char ***
|
|
|
d1c05f |
static char **
|
|
|
d1c05f |
do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
|
|
d1c05f |
{
|
|
|
d1c05f |
- char buf[256];
|
|
|
d1c05f |
+ char buf[SSH_MAX_PUBKEY_BYTES];
|
|
|
d1c05f |
+ char *pbuf = &buf[0];
|
|
|
d1c05f |
size_t n;
|
|
|
d1c05f |
u_int i, envsize;
|
|
|
d1c05f |
char *ocp, *cp, *value, **env, *laddr;
|
|
|
d1c05f |
struct passwd *pw = s->pw;
|
|
|
d1c05f |
+ Authctxt *authctxt = s->authctxt;
|
|
|
d1c05f |
+ struct sshkey *key;
|
|
|
d1c05f |
+ size_t len = 0;
|
|
|
d1c05f |
+ ssize_t total = 0;
|
|
|
d1c05f |
+ struct sshkey_cert *cert;
|
|
|
d1c05f |
+
|
|
|
d1c05f |
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
|
|
|
d1c05f |
char *path = NULL;
|
|
|
d1c05f |
#endif
|
|
|
f94360 |
@@ -1255,9 +1263,57 @@ do_setup_env(struct ssh *ssh, Session *s
|
|
|
d1c05f |
child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
|
|
|
d1c05f |
if (s->ttyfd != -1)
|
|
|
d1c05f |
child_set_env(&env, &envsize, "SSH_TTY", s->tty);
|
|
|
d1c05f |
- if (original_command)
|
|
|
d1c05f |
+ if (original_command) {
|
|
|
d1c05f |
child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
|
|
|
d1c05f |
original_command);
|
|
|
d1c05f |
+ /*
|
|
|
d1c05f |
+ * Set SSH_CERT_PRINCIPALS to be the principals on the ssh certificate.
|
|
|
d1c05f |
+ * Only do so when a force command is present to prevent the client
|
|
|
d1c05f |
+ * from changing the value of SSH_CERT_PRINCIPALS. For example, when a
|
|
|
d1c05f |
+ * client is given shell access, the client can easily change the
|
|
|
d1c05f |
+ * value of an environment variable by running, e.g.,
|
|
|
d1c05f |
+ * ssh user@host.address 'SSH_CERT_PRINCIPALS=attacker env'
|
|
|
d1c05f |
+ */
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ if (authctxt->nprev_keys > 0) {
|
|
|
d1c05f |
+ key = authctxt->prev_keys[authctxt->nprev_keys-1];
|
|
|
d1c05f |
+ /* If a user was authorized by a certificate, set SSH_CERT_PRINCIPALS */
|
|
|
d1c05f |
+ if (sshkey_is_cert(key)) {
|
|
|
d1c05f |
+ cert = key->cert;
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ for (i = 0; i < cert->nprincipals - 1; ++i) {
|
|
|
d1c05f |
+ /*
|
|
|
d1c05f |
+ * total: bytes written to buf so far
|
|
|
d1c05f |
+ * 2: one for comma and one for '\0' to be added by snprintf
|
|
|
d1c05f |
+ * We stop at the first principal overflowing buf.
|
|
|
d1c05f |
+ */
|
|
|
d1c05f |
+ if (total + strlen(cert->principals[i]) + 2 > SSH_MAX_PUBKEY_BYTES)
|
|
|
d1c05f |
+ break;
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ len = snprintf(pbuf, SSH_MAX_PUBKEY_BYTES-total, "%s,",
|
|
|
d1c05f |
+ cert->principals[i]);
|
|
|
d1c05f |
+ /* pbuf advances by len, the '\0' at the end will be overwritten */
|
|
|
d1c05f |
+ pbuf += len;
|
|
|
d1c05f |
+ total += len;
|
|
|
d1c05f |
+ }
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ if (total + strlen(cert->principals[i]) + 1 <= SSH_MAX_PUBKEY_BYTES) {
|
|
|
d1c05f |
+ len = snprintf(pbuf, SSH_MAX_PUBKEY_BYTES-total, "%s",
|
|
|
d1c05f |
+ cert->principals[i]);
|
|
|
d1c05f |
+ total += len;
|
|
|
d1c05f |
+ } else if (total > 0)
|
|
|
d1c05f |
+ /*
|
|
|
d1c05f |
+ * If we hit the overflow condition, remove the trailing comma.
|
|
|
d1c05f |
+ * We only do so if the overflowing principal is not the first one on the
|
|
|
d1c05f |
+ * certificate so that there is at least one principal in buf
|
|
|
d1c05f |
+ */
|
|
|
d1c05f |
+ buf[total-1] = '\0';
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ if (total > 0)
|
|
|
d1c05f |
+ child_set_env(&env, &envsize, "SSH_CERT_PRINCIPALS", buf);
|
|
|
d1c05f |
+ }
|
|
|
d1c05f |
+ }
|
|
|
d1c05f |
+ }
|
|
|
d1c05f |
|
|
|
2540e6 |
/* set LOG_SESSION_ID for child */
|
|
|
2540e6 |
child_set_env(&env, &envsize, "LOG_SESSION_ID", get_log_session_id());
|
|
|
d1c05f |
--- /dev/null
|
|
|
d1c05f |
+++ b/regress/cert-princ-env.sh
|
|
|
d1c05f |
@@ -0,0 +1,129 @@
|
|
|
d1c05f |
+tid="cert principal env"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# change to ecdsa
|
|
|
d1c05f |
+CERT_ID="$USER"
|
|
|
d1c05f |
+AUTH_PRINC_FILE="$OBJ/auth_principals"
|
|
|
d1c05f |
+CA_FILE="$OBJ/ca-rsa"
|
|
|
d1c05f |
+IDENTITY_FILE="$OBJ/$USER-rsa"
|
|
|
d1c05f |
+SSH_MAX_PUBKEY_BYTES=16384
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+cat << EOF >> $OBJ/sshd_config
|
|
|
d1c05f |
+TrustedUserCAKeys $CA_FILE.pub
|
|
|
d1c05f |
+Protocol 2
|
|
|
d1c05f |
+PubkeyAuthentication yes
|
|
|
d1c05f |
+AuthenticationMethods publickey
|
|
|
d1c05f |
+AuthorizedPrincipalsFile $AUTH_PRINC_FILE
|
|
|
d1c05f |
+ForceCommand=/bin/env
|
|
|
d1c05f |
+EOF
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+cleanup() {
|
|
|
d1c05f |
+ rm -f $CA_FILE{.pub,}
|
|
|
d1c05f |
+ rm -f $IDENTITY_FILE{-cert.pub,.pub,}
|
|
|
d1c05f |
+ rm -f $AUTH_PRINC_FILE
|
|
|
d1c05f |
+}
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+make_keys_and_certs() {
|
|
|
d1c05f |
+ rm -f $CA_FILE{.pub,}
|
|
|
d1c05f |
+ rm -f $IDENTITY_FILE{-cert.pub,.pub,}
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ local princs=$1
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ ${SSHKEYGEN} -q -t rsa -C '' -N '' -f $CA_FILE ||
|
|
|
d1c05f |
+ fatal 'Could not create CA key'
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ ${SSHKEYGEN} -q -t rsa -C '' -N '' -f $IDENTITY_FILE ||
|
|
|
d1c05f |
+ fatal 'Could not create keypair'
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ ${SSHKEYGEN} -q -s $CA_FILE -I $CERT_ID -n "$princs" -z "42" "$IDENTITY_FILE.pub" ||
|
|
|
d1c05f |
+ fatal "Could not create SSH cert"
|
|
|
d1c05f |
+}
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+test_with_expected_principals() {
|
|
|
d1c05f |
+ local princs=$1
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ out=$(${SSH} -E thlog -F $OBJ/ssh_config -i "$IDENTITY_FILE" somehost false) ||
|
|
|
d1c05f |
+ fatal "SSH failed"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ echo "$out" | grep -q "SSH_CERT_PRINCIPALS=$princs$" ||
|
|
|
d1c05f |
+ fatal "SSH_CERT_PRINCIPALS has incorrect value"
|
|
|
d1c05f |
+}
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+test_with_no_expected_principals() {
|
|
|
d1c05f |
+ local princs=$1
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ out=$(${SSH} -E thlog -F $OBJ/ssh_config -i "$IDENTITY_FILE" somehost false) ||
|
|
|
d1c05f |
+ fatal "SSH failed"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ echo "$out" | grep -vq "SSH_CERT_PRINCIPALS" ||
|
|
|
d1c05f |
+ fatal "SSH_CERT_PRINCIPALS env should not be set"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+ echo "$out" | grep -vq "SSH_CERT_PRINCIPALS=$princs" ||
|
|
|
d1c05f |
+ fatal "SSH_CERT_PRINCIPALS has incorrect value"
|
|
|
d1c05f |
+}
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+echo 'a' > $AUTH_PRINC_FILE
|
|
|
d1c05f |
+start_sshd
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+principals="a,b,c,d"
|
|
|
d1c05f |
+make_keys_and_certs "$principals"
|
|
|
d1c05f |
+test_with_expected_principals "$principals"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+big_princ=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16381 | head -n 1)
|
|
|
d1c05f |
+make_keys_and_certs "a,$big_princ"
|
|
|
d1c05f |
+test_with_expected_principals "a,$big_princ"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# No room for two principals
|
|
|
d1c05f |
+big_princ=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16382 | head -n 1)
|
|
|
d1c05f |
+make_keys_and_certs "a,$big_princ"
|
|
|
d1c05f |
+test_with_expected_principals "a"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+make_keys_and_certs "$big_princ,a"
|
|
|
d1c05f |
+test_with_expected_principals "$big_princ"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+big_princ=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16384 | head -n 1)
|
|
|
d1c05f |
+make_keys_and_certs "a,$big_princ"
|
|
|
d1c05f |
+test_with_expected_principals "a"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# principal too big for buffer
|
|
|
d1c05f |
+big_princ=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $SSH_MAX_PUBKEY_BYTES | head -n 1)
|
|
|
d1c05f |
+make_keys_and_certs "$big_princ"
|
|
|
d1c05f |
+test_with_no_expected_principals "$big_princ"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# no matching principals in certificate and auth princ file
|
|
|
d1c05f |
+principals="b,c,d"
|
|
|
d1c05f |
+make_keys_and_certs "$principals"
|
|
|
d1c05f |
+test_with_no_expected_principals "$principals"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+stop_sshd
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+cat << EOF >> $OBJ/sshd_config
|
|
|
d1c05f |
+TrustedUserCAKeys $CA_FILE.pub
|
|
|
d1c05f |
+Protocol 2
|
|
|
d1c05f |
+PubkeyAuthentication yes
|
|
|
d1c05f |
+AuthenticationMethods publickey
|
|
|
d1c05f |
+AuthorizedPrincipalsFile $AUTH_PRINC_FILE
|
|
|
d1c05f |
+EOF
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+start_sshd
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# no force command, no princpals
|
|
|
d1c05f |
+principals="a,b,c,d"
|
|
|
d1c05f |
+make_keys_and_certs "$principals"
|
|
|
d1c05f |
+test_with_no_expected_principals "$principals"
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+stop_sshd
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+cat << EOF >> $OBJ/sshd_config
|
|
|
d1c05f |
+Protocol 2
|
|
|
d1c05f |
+PubkeyAuthentication yes
|
|
|
d1c05f |
+AuthenticationMethods publickey
|
|
|
d1c05f |
+AuthorizedPrincipalsFile $AUTH_PRINC_FILE
|
|
|
d1c05f |
+EOF
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+start_sshd
|
|
|
d1c05f |
+
|
|
|
d1c05f |
+# No TrustedUserCAKeys causes pubkey auth, no principals
|
|
|
d1c05f |
+principals="a,b,c,d"
|
|
|
d1c05f |
+make_keys_and_certs "$principals"
|
|
|
d1c05f |
+test_with_no_expected_principals "$principals"
|