From 1b8a267cb916f20439043dacc4e2a90253bbb59f Mon Sep 17 00:00:00 2001 From: Jan F. Chadima Date: Aug 03 2010 00:41:49 +0000 Subject: Upgrade to openssh-5.6p1 --- diff --git a/openssh-4.0p1-exit-deadlock.patch b/openssh-4.0p1-exit-deadlock.patch deleted file mode 100644 index 66246d3..0000000 --- a/openssh-4.0p1-exit-deadlock.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- openssh-4.0p1/channels.c.exit-deadlock 2005-03-01 11:24:33.000000000 +0100 -+++ openssh-4.0p1/channels.c 2005-04-05 22:25:15.197226237 +0200 -@@ -1403,6 +1403,10 @@ - u_int dlen; - int len; - -+ if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { -+ debug("channel %d: forcing write", c->self); -+ FD_SET(c->wfd, writeset); -+ } - /* Send buffered output data to the socket. */ - if (c->wfd != -1 && - FD_ISSET(c->wfd, writeset) && diff --git a/openssh-5.3p1-selabel.patch b/openssh-5.3p1-selabel.patch deleted file mode 100644 index 6e5d6bd..0000000 --- a/openssh-5.3p1-selabel.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff -up openssh-5.3p1/contrib/ssh-copy-id.selabel openssh-5.3p1/contrib/ssh-copy-id ---- openssh-5.3p1/contrib/ssh-copy-id.selabel 2009-01-21 10:29:21.000000000 +0100 -+++ openssh-5.3p1/contrib/ssh-copy-id 2009-10-02 14:21:54.000000000 +0200 -@@ -38,7 +38,7 @@ if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || - exit 1 - fi - --{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys" || exit 1 -+{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys; test -x /sbin/restorecon && /sbin/restorecon .ssh .ssh/authorized_keys" || exit 1 - - cat < - #include - #include -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" - -@@ -792,10 +793,15 @@ main(int ac, char **av) - */ - r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, - strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); -- if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) -+ if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { -+ char *scon; -+ -+ matchpathcon(buf, 0700, &scon); -+ setfscreatecon(scon); - if (mkdir(buf, 0700) < 0) - error("Could not create directory '%.200s'.", buf); -- -+ setfscreatecon(NULL); -+ } - /* load options.identity_files */ - load_public_identity_files(); - diff --git a/openssh-5.3p1-skip-initial.patch b/openssh-5.3p1-skip-initial.patch deleted file mode 100644 index d52962e..0000000 --- a/openssh-5.3p1-skip-initial.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -up openssh-5.3p1/auth1.c.skip-initial openssh-5.3p1/auth1.c ---- openssh-5.3p1/auth1.c.skip-initial 2009-03-08 01:40:28.000000000 +0100 -+++ openssh-5.3p1/auth1.c 2009-10-02 13:55:00.000000000 +0200 -@@ -244,7 +244,7 @@ do_authloop(Authctxt *authctxt) - authctxt->valid ? "" : "invalid user ", authctxt->user); - - /* If the user has no password, accept authentication immediately. */ -- if (options.password_authentication && -+ if (options.permit_empty_passwd && options.password_authentication && - #ifdef KRB5 - (!options.kerberos_authentication || options.kerberos_or_local_passwd) && - #endif -diff -up openssh-5.3p1/auth2-none.c.skip-initial openssh-5.3p1/auth2-none.c ---- openssh-5.3p1/auth2-none.c.skip-initial 2009-03-08 01:40:28.000000000 +0100 -+++ openssh-5.3p1/auth2-none.c 2009-10-02 13:56:21.000000000 +0200 -@@ -61,7 +61,7 @@ userauth_none(Authctxt *authctxt) - { - none_enabled = 0; - packet_check_eom(); -- if (options.password_authentication) -+ if (options.permit_empty_passwd && options.password_authentication) - return (PRIVSEP(auth_password(authctxt, ""))); - return (0); - } diff --git a/openssh-5.5p1-authorized-keys-command.patch b/openssh-5.5p1-authorized-keys-command.patch deleted file mode 100644 index 8be37fd..0000000 --- a/openssh-5.5p1-authorized-keys-command.patch +++ /dev/null @@ -1,440 +0,0 @@ -diff -ruN openssh-5.5p1.orig/auth2-pubkey.c openssh-5.5p1/auth2-pubkey.c ---- openssh-5.5p1.orig/auth2-pubkey.c 2010-03-21 14:51:21.000000000 -0400 -+++ openssh-5.5p1/auth2-pubkey.c 2010-07-03 20:23:43.000000000 -0400 -@@ -27,6 +27,7 @@ - - #include - #include -+#include - - #include - #include -@@ -178,27 +178,15 @@ - - /* return 1 if user allows given key */ - static int --user_key_allowed2(struct passwd *pw, Key *key, char *file) -+user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw) - { - char line[SSH_MAX_PUBKEY_BYTES]; - const char *reason; - int found_key = 0; -- FILE *f; - u_long linenum = 0; - Key *found; - char *fp; - -- /* Temporarily use the user's uid. */ -- temporarily_use_uid(pw); -- -- debug("trying public key file %s", file); -- f = auth_openkeyfile(file, pw, options.strict_modes); -- -- if (!f) { -- restore_uid(); -- return 0; -- } -- - found_key = 0; - found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); - -@@ -273,8 +261,6 @@ - break; - } - } -- restore_uid(); -- fclose(f); - key_free(found); - if (!found_key) - debug2("key not found"); -@@ -321,13 +307,191 @@ - return ret; - } - --/* check whether given key is in .ssh/authorized_keys* */ -+/* return 1 if user allows given key */ -+static int -+user_key_allowed2(struct passwd *pw, Key *key, char *file) -+{ -+ FILE *f; -+ int found_key = 0; -+ -+ /* Temporarily use the user's uid. */ -+ temporarily_use_uid(pw); -+ -+ debug("trying public key file %s", file); -+ f = auth_openkeyfile(file, pw, options.strict_modes); -+ -+ if (f) { -+ found_key = user_search_key_in_file (f, file, key, pw); -+ fclose(f); -+ } -+ -+ restore_uid(); -+ return found_key; -+} -+ -+#ifdef WITH_AUTHORIZED_KEYS_COMMAND -+ -+#define WHITESPACE " \t\r\n" -+ -+/* return 1 if user allows given key */ -+static int -+user_key_via_command_allowed2(struct passwd *pw, Key *key) -+{ -+ FILE *f; -+ int found_key = 0; -+ char *progname = NULL; -+ char *cp; -+ struct passwd *runas_pw; -+ struct stat st; -+ int childdescriptors[2], i; -+ pid_t pstat, pid, child; -+ -+ if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/') -+ return -1; -+ -+ /* get the run as identity from config */ -+ runas_pw = (options.authorized_keys_command_runas == NULL)? pw -+ : getpwnam (options.authorized_keys_command_runas); -+ if (!runas_pw) { -+ error("%s: getpwnam(\"%s\"): %s", __func__, -+ options.authorized_keys_command_runas, strerror(errno)); -+ return 0; -+ } -+ -+ /* Temporarily use the specified uid. */ -+ if (runas_pw->pw_uid != 0) -+ temporarily_use_uid(runas_pw); -+ -+ progname = xstrdup(options.authorized_keys_command); -+ -+ debug3("%s: checking program '%s'", __func__, progname); -+ -+ if (stat (progname, &st) < 0) { -+ error("%s: stat(\"%s\"): %s", __func__, -+ progname, strerror(errno)); -+ goto go_away; -+ } -+ -+ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { -+ error("bad ownership or modes for AuthorizedKeysCommand \"%s\"", -+ progname); -+ goto go_away; -+ } -+ -+ if (!S_ISREG(st.st_mode)) { -+ error("AuthorizedKeysCommand \"%s\" is not a regular file", -+ progname); -+ goto go_away; -+ } -+ -+ /* -+ * Descend the path, checking that each component is a -+ * root-owned directory with strict permissions. -+ */ -+ do { -+ if ((cp = strrchr(progname, '/')) == NULL) -+ break; -+ else -+ *cp = '\0'; -+ -+ debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname)); -+ -+ if (stat((*progname == '\0' ? "/" : progname), &st) != 0) { -+ error("%s: stat(\"%s\"): %s", __func__, -+ progname, strerror(errno)); -+ goto go_away; -+ } -+ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { -+ error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"", -+ progname); -+ goto go_away; -+ } -+ if (!S_ISDIR(st.st_mode)) { -+ error("AuthorizedKeysCommand path component \"%s\" is not a directory", -+ progname); -+ goto go_away; -+ } -+ } while (1); -+ -+ /* open the pipe and read the keys */ -+ if (pipe(childdescriptors)) { -+ error("failed to pipe(2) for AuthorizedKeysCommand: %s", -+ strerror(errno)); -+ goto go_away; -+ } -+ -+ child = fork(); -+ if (child == -1) { -+ error("failed to fork(2) for AuthorizedKeysCommand: %s", -+ strerror(errno)); -+ goto go_away; -+ } else if (child == 0) { -+ /* we're in the child process here -- we should never return from this block. */ -+ /* permanently drop privs in child process */ -+ if (runas_pw->pw_uid != 0) { -+ restore_uid(); -+ permanently_set_uid(runas_pw); -+ } -+ -+ close(childdescriptors[0]); -+ /* put the write end of the pipe on stdout (FD 1) */ -+ if (dup2(childdescriptors[1], 1) == -1) { -+ error("failed to dup2(2) from AuthorizedKeysCommand: %s", -+ strerror(errno)); -+ _exit(127); -+ } -+ -+ debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name); -+ /* see session.c:child_close_fds() */ -+ for (i = 3; i < 64; ++i) { -+ close(i); -+ } -+ -+ execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL); -+ -+ /* if we got here, it didn't work */ -+ error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */ -+ _exit(127); -+ } -+ -+ close(childdescriptors[1]); -+ f = fdopen(childdescriptors[0], "r"); -+ if (!f) { -+ error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__, -+ options.authorized_keys_command, strerror (errno)); -+ goto go_away; -+ } -+ -+ found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw); -+ fclose (f); -+ do { -+ pid = waitpid(child, &pstat, 0); -+ } while (pid == -1 && errno == EINTR); -+ -+ /* what about the return value from the child process? */ -+go_away: -+ if (progname) -+ xfree (progname); -+ -+ if (runas_pw->pw_uid != 0) -+ restore_uid(); -+ return found_key; -+} -+#endif -+ -+/* check whether given key is in 0) -+ return success; -+#endif -+ - if (auth_key_is_revoked(key)) - return 0; - if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) -diff -ruN openssh-5.5p1.orig/configure.ac openssh-5.5p1/configure.ac ---- openssh-5.5p1.orig/configure.ac 2010-04-10 08:58:01.000000000 -0400 -+++ openssh-5.5p1/configure.ac 2010-07-03 19:57:42.000000000 -0400 -@@ -1346,6 +1346,18 @@ - esac ] - ) - -+# Check whether user wants AuthorizedKeysCommand support -+AKC_MSG="no" -+AC_ARG_WITH(authorized-keys-command, -+ [ --with-authorized-keys-command Enable AuthorizedKeysCommand support], -+ [ -+ if test "x$withval" != "xno" ; then -+ AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support]) -+ AKC_MSG="yes" -+ fi -+ ] -+) -+ - dnl Checks for library functions. Please keep in alphabetical order - AC_CHECK_FUNCS( \ - arc4random \ -@@ -4181,6 +4193,7 @@ - echo " Smartcard support: $SCARD_MSG" - echo " S/KEY support: $SKEY_MSG" - echo " TCP Wrappers support: $TCPW_MSG" -+echo " AuthorizedKeysCommand support: $AKC_MSG" - echo " MD5 password support: $MD5_MSG" - echo " libedit support: $LIBEDIT_MSG" - echo " Solaris process contract support: $SPC_MSG" -diff -ruN openssh-5.5p1.orig/servconf.c openssh-5.5p1/servconf.c ---- openssh-5.5p1.orig/servconf.c 2010-03-25 19:40:04.000000000 -0400 -+++ openssh-5.5p1/servconf.c 2010-07-03 19:59:07.000000000 -0400 -@@ -128,6 +128,8 @@ - options->num_permitted_opens = -1; - options->adm_forced_command = NULL; - options->chroot_directory = NULL; -+ options->authorized_keys_command = NULL; -+ options->authorized_keys_command_runas = NULL; - options->zero_knowledge_password_authentication = -1; - options->revoked_keys_file = NULL; - options->trusted_user_ca_keys = NULL; -@@ -311,6 +313,7 @@ - sUsePrivilegeSeparation, sAllowAgentForwarding, - sZeroKnowledgePasswordAuthentication, sHostCertificate, - sRevokedKeys, sTrustedUserCAKeys, -+ sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs, - sDeprecated, sUnsupported - } ServerOpCodes; - -@@ -432,6 +435,13 @@ - { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, - { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, - { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, -+#ifdef WITH_AUTHORIZED_KEYS_COMMAND -+ { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, -+ { "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL }, -+#else -+ { "authorizedkeyscommand", sUnsupported, SSHCFG_ALL }, -+ { "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL }, -+#endif - { NULL, sBadOption, 0 } - }; - -@@ -1345,6 +1355,20 @@ - charptr = &options->revoked_keys_file; - goto parse_filename; - -+ case sAuthorizedKeysCommand: -+ len = strspn(cp, WHITESPACE); -+ if (*activep && options->authorized_keys_command == NULL) -+ options->authorized_keys_command = xstrdup(cp + len); -+ return 0; -+ -+ case sAuthorizedKeysCommandRunAs: -+ charptr = &options->authorized_keys_command_runas; -+ -+ arg = strdelim(&cp); -+ if (*activep && *charptr == NULL) -+ *charptr = xstrdup(arg); -+ break; -+ - case sDeprecated: - logit("%s line %d: Deprecated option %s", - filename, linenum, arg); -@@ -1438,6 +1462,8 @@ - M_CP_INTOPT(gss_authentication); - M_CP_INTOPT(rsa_authentication); - M_CP_INTOPT(pubkey_authentication); -+ M_CP_STROPT(authorized_keys_command); -+ M_CP_STROPT(authorized_keys_command_runas); - M_CP_INTOPT(kerberos_authentication); - M_CP_INTOPT(hostbased_authentication); - M_CP_INTOPT(kbd_interactive_authentication); -@@ -1682,6 +1708,8 @@ - dump_cfg_string(sChrootDirectory, o->chroot_directory); - dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); - dump_cfg_string(sRevokedKeys, o->revoked_keys_file); -+ dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); -+ dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas); - - /* string arguments requiring a lookup */ - dump_cfg_string(sLogLevel, log_level_name(o->log_level)); -diff -ruN openssh-5.5p1.orig/servconf.h openssh-5.5p1/servconf.h ---- openssh-5.5p1.orig/servconf.h 2010-03-04 05:53:35.000000000 -0500 -+++ openssh-5.5p1/servconf.h 2010-07-03 19:57:42.000000000 -0400 -@@ -156,6 +156,8 @@ - char *chroot_directory; - char *revoked_keys_file; - char *trusted_user_ca_keys; -+ char *authorized_keys_command; -+ char *authorized_keys_command_runas; - } ServerOptions; - - void initialize_server_options(ServerOptions *); -diff -ruN openssh-5.5p1.orig/sshd_config openssh-5.5p1/sshd_config ---- openssh-5.5p1.orig/sshd_config 2009-10-11 06:51:09.000000000 -0400 -+++ openssh-5.5p1/sshd_config 2010-07-03 19:57:42.000000000 -0400 -@@ -44,6 +44,8 @@ - #RSAAuthentication yes - #PubkeyAuthentication yes - #AuthorizedKeysFile .ssh/authorized_keys -+#AuthorizedKeysCommand none -+#AuthorizedKeysCommandRunAs nobody - - # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts - #RhostsRSAAuthentication no -diff -ruN openssh-5.5p1.orig/sshd_config.0 openssh-5.5p1/sshd_config.0 ---- openssh-5.5p1.orig/sshd_config.0 2010-04-15 20:17:12.000000000 -0400 -+++ openssh-5.5p1/sshd_config.0 2010-07-03 19:57:42.000000000 -0400 -@@ -352,7 +352,8 @@ - KbdInteractiveAuthentication, KerberosAuthentication, - MaxAuthTries, MaxSessions, PasswordAuthentication, - PermitEmptyPasswords, PermitOpen, PermitRootLogin, -- PubkeyAuthentication, RhostsRSAAuthentication, RSAAuthentication, -+ PubkeyAuthentication, AuthorizedKeysCommand, AuthorizedKeysCommandRunAs, -+ RhostsRSAAuthentication, RSAAuthentication, - X11DisplayOffset, X11Forwarding and X11UseLocalHost. - - MaxAuthTries -@@ -467,6 +468,23 @@ - this file is not readable, then public key authentication will be - refused for all users. - -+ AuthorizedKeysCommand -+ -+ Specifies a program to be used for lookup of the user's -+ public keys. The program will be invoked with its first -+ argument the name of the user being authorized, and should produce -+ on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS -+ in sshd(8)). By default (or when set to the empty string) there is no -+ AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully -+ authorize the user, authorization falls through to the -+ AuthorizedKeysFile. Note that this option has an effect -+ only with PubkeyAuthentication turned on. -+ -+ AuthorizedKeysCommandRunAs -+ Specifies the user under whose account the AuthorizedKeysCommand is run. -+ Empty string (the default value) means the user being authorized -+ is used. -+ - RhostsRSAAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication to- - gether with successful RSA host authentication is allowed. The -diff -ruN openssh-5.5p1.orig/sshd_config.5 openssh-5.5p1/sshd_config.5 ---- openssh-5.5p1.orig/sshd_config.5 2010-03-04 18:41:45.000000000 -0500 -+++ openssh-5.5p1/sshd_config.5 2010-07-03 19:57:42.000000000 -0400 -@@ -618,6 +618,9 @@ - .Cm KerberosAuthentication , - .Cm MaxAuthTries , - .Cm MaxSessions , -+.Cm PubkeyAuthentication , -+.Cm AuthorizedKeysCommand , -+.Cm AuthorizedKeysCommandRunAs , - .Cm PasswordAuthentication , - .Cm PermitEmptyPasswords , - .Cm PermitOpen , -@@ -819,6 +822,20 @@ - Keys listed in this file will be refused for public key authentication. - Note that if this file is not readable, then public key authentication will - be refused for all users. -+.It Cm AuthorizedKeysCommand -+Specifies a program to be used for lookup of the user's -+public keys. The program will be invoked with its first -+argument the name of the user being authorized, and should produce -+on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS -+in sshd(8)). By default (or when set to the empty string) there is no -+AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully -+authorize the user, authorization falls through to the -+AuthorizedKeysFile. Note that this option has an effect -+only with PubkeyAuthentication turned on. -+.It Cm AuthorizedKeysCommandRunAs -+Specifies the user under whose account the AuthorizedKeysCommand is run. Empty -+string (the default value) means the user being authorized is used. -+.Dq - .It Cm RhostsRSAAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication together - with successful RSA host authentication is allowed. diff --git a/openssh-5.5p1-fips.patch b/openssh-5.5p1-fips.patch deleted file mode 100644 index 2f6db6f..0000000 --- a/openssh-5.5p1-fips.patch +++ /dev/null @@ -1,686 +0,0 @@ -diff -up openssh-5.5p1/auth2-pubkey.c.fips openssh-5.5p1/auth2-pubkey.c ---- openssh-5.5p1/auth2-pubkey.c.fips 2010-04-16 08:46:47.000000000 +0200 -+++ openssh-5.5p1/auth2-pubkey.c 2010-04-16 08:46:48.000000000 +0200 -@@ -35,6 +35,7 @@ - #include - #include - #include -+#include - - #include "xmalloc.h" - #include "ssh.h" -@@ -274,7 +275,7 @@ user_key_allowed2(struct passwd *pw, Key - found_key = 1; - debug("matching key found: file %s, line %lu", - file, linenum); -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(found, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); - verbose("Found matching %s key: %s", - key_type(found), fp); - xfree(fp); -diff -up openssh-5.5p1/authfile.c.fips openssh-5.5p1/authfile.c ---- openssh-5.5p1/authfile.c.fips 2010-03-04 11:53:35.000000000 +0100 -+++ openssh-5.5p1/authfile.c 2010-04-16 08:46:49.000000000 +0200 -@@ -146,8 +146,14 @@ key_save_private_rsa1(Key *key, const ch - /* Allocate space for the private part of the key in the buffer. */ - cp = buffer_append_space(&encrypted, buffer_len(&buffer)); - -- cipher_set_key_string(&ciphercontext, cipher, passphrase, -- CIPHER_ENCRYPT); -+ if (cipher_set_key_string(&ciphercontext, cipher, passphrase, -+ CIPHER_ENCRYPT) < 0) { -+ error("cipher_set_key_string failed."); -+ buffer_free(&encrypted); -+ buffer_free(&buffer); -+ return 0; -+ } -+ - cipher_crypt(&ciphercontext, cp, - buffer_ptr(&buffer), buffer_len(&buffer)); - cipher_cleanup(&ciphercontext); -@@ -421,8 +427,14 @@ key_load_private_rsa1(int fd, const char - cp = buffer_append_space(&decrypted, buffer_len(&buffer)); - - /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ -- cipher_set_key_string(&ciphercontext, cipher, passphrase, -- CIPHER_DECRYPT); -+ if (cipher_set_key_string(&ciphercontext, cipher, passphrase, -+ CIPHER_DECRYPT) < 0) { -+ error("cipher_set_key_string failed."); -+ buffer_free(&decrypted); -+ buffer_free(&buffer); -+ goto fail; -+ } -+ - cipher_crypt(&ciphercontext, cp, - buffer_ptr(&buffer), buffer_len(&buffer)); - cipher_cleanup(&ciphercontext); -diff -up openssh-5.5p1/cipher.c.fips openssh-5.5p1/cipher.c ---- openssh-5.5p1/cipher.c.fips 2010-04-16 08:34:06.000000000 +0200 -+++ openssh-5.5p1/cipher.c 2010-04-16 08:46:49.000000000 +0200 -@@ -40,6 +40,7 @@ - #include - - #include -+#include - - #include - #include -@@ -93,6 +94,22 @@ struct Cipher { - { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } - }; - -+struct Cipher fips_ciphers[] = { -+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null }, -+ { "3des", SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des }, -+ -+ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc }, -+ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc }, -+ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc }, -+ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, -+ { "rijndael-cbc@lysator.liu.se", -+ SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, -+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr }, -+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr }, -+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr }, -+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } -+}; -+ - /*--*/ - - u_int -@@ -135,7 +152,7 @@ Cipher * - cipher_by_name(const char *name) - { - Cipher *c; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (strcmp(c->name, name) == 0) - return c; - return NULL; -@@ -145,7 +162,7 @@ Cipher * - cipher_by_number(int id) - { - Cipher *c; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (c->number == id) - return c; - return NULL; -@@ -189,7 +206,7 @@ cipher_number(const char *name) - Cipher *c; - if (name == NULL) - return -1; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (strcasecmp(c->name, name) == 0) - return c->number; - return -1; -@@ -296,14 +313,15 @@ cipher_cleanup(CipherContext *cc) - * passphrase and using the resulting 16 bytes as the key. - */ - --void -+int - cipher_set_key_string(CipherContext *cc, Cipher *cipher, - const char *passphrase, int do_encrypt) - { - MD5_CTX md; - u_char digest[16]; - -- MD5_Init(&md); -+ if (MD5_Init(&md) <= 0) -+ return -1; - MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); - MD5_Final(digest, &md); - -@@ -311,6 +329,7 @@ cipher_set_key_string(CipherContext *cc, - - memset(digest, 0, sizeof(digest)); - memset(&md, 0, sizeof(md)); -+ return 0; - } - - /* -diff -up openssh-5.5p1/cipher-ctr.c.fips openssh-5.5p1/cipher-ctr.c ---- openssh-5.5p1/cipher-ctr.c.fips 2007-06-14 15:21:33.000000000 +0200 -+++ openssh-5.5p1/cipher-ctr.c 2010-04-16 08:46:49.000000000 +0200 -@@ -140,7 +140,8 @@ evp_aes_128_ctr(void) - aes_ctr.do_cipher = ssh_aes_ctr; - #ifndef SSH_OLD_EVP - aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | -- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; -+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV | -+ EVP_CIPH_FLAG_FIPS; - #endif - return (&aes_ctr); - } -diff -up openssh-5.5p1/cipher.h.fips openssh-5.5p1/cipher.h ---- openssh-5.5p1/cipher.h.fips 2009-01-28 06:38:41.000000000 +0100 -+++ openssh-5.5p1/cipher.h 2010-04-16 08:46:49.000000000 +0200 -@@ -78,7 +78,7 @@ void cipher_init(CipherContext *, Ciphe - const u_char *, u_int, int); - void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); - void cipher_cleanup(CipherContext *); --void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); -+int cipher_set_key_string(CipherContext *, Cipher *, const char *, int); - u_int cipher_blocksize(const Cipher *); - u_int cipher_keylen(const Cipher *); - u_int cipher_is_cbc(const Cipher *); -diff -up openssh-5.5p1/mac.c.fips openssh-5.5p1/mac.c ---- openssh-5.5p1/mac.c.fips 2008-06-13 02:58:50.000000000 +0200 -+++ openssh-5.5p1/mac.c 2010-04-16 08:46:49.000000000 +0200 -@@ -28,6 +28,7 @@ - #include - - #include -+#include - - #include - #include -@@ -47,14 +48,14 @@ - #define SSH_EVP 1 /* OpenSSL EVP-based MAC */ - #define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ - --struct { -+struct Macs { - char *name; - int type; - const EVP_MD * (*mdfunc)(void); - int truncatebits; /* truncate digest if != 0 */ - int key_len; /* just for UMAC */ - int len; /* just for UMAC */ --} macs[] = { -+} all_macs[] = { - { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, - { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, -1, -1 }, - { "hmac-md5", SSH_EVP, EVP_md5, 0, -1, -1 }, -@@ -65,9 +66,15 @@ struct { - { NULL, 0, NULL, 0, -1, -1 } - }; - -+struct Macs fips_macs[] = { -+ { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, -+ { NULL, 0, NULL, 0, -1, -1 } -+}; -+ - static void - mac_setup_by_id(Mac *mac, int which) - { -+ struct Macs *macs = FIPS_mode() ? fips_macs : all_macs; - int evp_len; - mac->type = macs[which].type; - if (mac->type == SSH_EVP) { -@@ -88,6 +95,7 @@ int - mac_setup(Mac *mac, char *name) - { - int i; -+ struct Macs *macs = FIPS_mode() ? fips_macs : all_macs; - - for (i = 0; macs[i].name; i++) { - if (strcmp(name, macs[i].name) == 0) { -diff -up openssh-5.5p1/Makefile.in.fips openssh-5.5p1/Makefile.in ---- openssh-5.5p1/Makefile.in.fips 2010-03-13 22:41:34.000000000 +0100 -+++ openssh-5.5p1/Makefile.in 2010-04-16 09:48:16.000000000 +0200 -@@ -141,25 +141,25 @@ - $(RANLIB) $@ - - ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) -- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) -- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) -+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) - - scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o - $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) - - ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o -- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o -- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o -- $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o -- $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o - $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -@@ -168,7 +168,7 @@ - $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o -- $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -+ $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) - - sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o - $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -diff -up openssh-5.5p1/myproposal.h.fips openssh-5.5p1/myproposal.h ---- openssh-5.5p1/myproposal.h.fips 2010-02-26 21:55:05.000000000 +0100 -+++ openssh-5.5p1/myproposal.h 2010-04-16 08:46:49.000000000 +0200 -@@ -55,7 +55,12 @@ - "hmac-sha1-96,hmac-md5-96" - #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" - #define KEX_DEFAULT_LANG "" -- -+#define KEX_FIPS_ENCRYPT \ -+ "aes128-ctr,aes192-ctr,aes256-ctr," \ -+ "aes128-cbc,3des-cbc," \ -+ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" -+#define KEX_FIPS_MAC \ -+ "hmac-sha1" - - static char *myproposal[PROPOSAL_MAX] = { - KEX_DEFAULT_KEX, -diff -up openssh-5.5p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.5p1/openbsd-compat/bsd-arc4random.c ---- openssh-5.5p1/openbsd-compat/bsd-arc4random.c.fips 2010-03-25 22:52:02.000000000 +0100 -+++ openssh-5.5p1/openbsd-compat/bsd-arc4random.c 2010-04-16 09:17:30.000000000 +0200 -@@ -39,6 +39,7 @@ - static int rc4_ready = 0; - static RC4_KEY rc4; - -+#if 0 - unsigned int - arc4random(void) - { -@@ -82,6 +83,32 @@ arc4random_stir(void) - - rc4_ready = REKEY_BYTES; - } -+#else -+unsigned int -+arc4random(void) -+{ -+ unsigned int r = 0; -+ void *rp = &r; -+ -+ if (!rc4_ready) { -+ arc4random_stir(); -+ } -+ RAND_bytes(rp, sizeof(r)); -+ -+ return(r); -+} -+ -+void -+arc4random_stir(void) -+{ -+ unsigned char rand_buf[SEED_SIZE]; -+ -+ if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) -+ fatal("Couldn't obtain random bytes (error %ld)", -+ ERR_get_error()); -+ rc4_ready = 1; -+} -+#endif - #endif /* !HAVE_ARC4RANDOM */ - - #ifndef HAVE_ARC4RANDOM_BUF -diff -up openssh-5.5p1/ssh-add.c.fips openssh-5.5p1/ssh-add.c ---- openssh-5.5p1/ssh-add.c.fips 2010-03-03 00:25:42.000000000 +0100 -+++ openssh-5.5p1/ssh-add.c 2010-04-16 08:46:49.000000000 +0200 -@@ -42,6 +42,7 @@ - #include - - #include -+#include - #include "openbsd-compat/openssl-compat.h" - - #include -@@ -269,7 +270,7 @@ list_identities(AuthenticationConnection - key = ssh_get_next_identity(ac, &comment, version)) { - had_identities = 1; - if (do_fp) { -- fp = key_fingerprint(key, SSH_FP_MD5, -+ fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, - SSH_FP_HEX); - printf("%d %s %s (%s)\n", - key_size(key), fp, comment, key_type(key)); -diff -up openssh-5.5p1/ssh-agent.c.fips openssh-5.5p1/ssh-agent.c ---- openssh-5.5p1/ssh-agent.c.fips 2010-02-26 21:55:06.000000000 +0100 -+++ openssh-5.5p1/ssh-agent.c 2010-04-16 08:46:49.000000000 +0200 -@@ -51,6 +51,7 @@ - - #include - #include -+#include - #include "openbsd-compat/openssl-compat.h" - - #include -@@ -199,9 +200,9 @@ confirm_key(Identity *id) - char *p; - int ret = -1; - -- p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); -- if (ask_permission("Allow use of key %s?\nKey fingerprint %s.", -- id->comment, p)) -+ p = key_fingerprint(id->key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); -+ if (ask_permission("Allow use of key %s?\nKey %sfingerprint %s.", -+ id->comment, FIPS_mode() ? "SHA1 " : "", p)) - ret = 0; - xfree(p); - -diff -up openssh-5.5p1/ssh.c.fips openssh-5.5p1/ssh.c ---- openssh-5.5p1/ssh.c.fips 2010-02-26 21:55:06.000000000 +0100 -+++ openssh-5.5p1/ssh.c 2010-04-16 08:46:49.000000000 +0200 -@@ -72,6 +72,8 @@ - - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" - -@@ -225,6 +227,10 @@ main(int ac, char **av) - sanitise_stdfd(); - - __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); -+ if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) { -+ fatal("FIPS integrity verification test failed."); -+ } - init_rng(); - - /* -@@ -285,6 +291,9 @@ main(int ac, char **av) - "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { - switch (opt) { - case '1': -+ if (FIPS_mode()) { -+ fatal("Protocol 1 not allowed in the FIPS mode."); -+ } - options.protocol = SSH_PROTO_1; - break; - case '2': -@@ -581,7 +590,6 @@ main(int ac, char **av) - if (!host) - usage(); - -- SSLeay_add_all_algorithms(); - ERR_load_crypto_strings(); - - /* Initialize the command to execute on remote host. */ -@@ -667,6 +675,10 @@ main(int ac, char **av) - - seed_rng(); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - if (options.user == NULL) - options.user = xstrdup(pw->pw_name); - -@@ -733,6 +745,12 @@ main(int ac, char **av) - - timeout_ms = options.connection_timeout * 1000; - -+ if (FIPS_mode()) { -+ options.protocol &= SSH_PROTO_2; -+ if (options.protocol == 0) -+ fatal("Protocol 2 disabled by configuration but required in the FIPS mode."); -+ } -+ - /* Open a connection to the remote host. */ - if (ssh_connect(host, &hostaddr, options.port, - options.address_family, options.connection_attempts, &timeout_ms, -diff -up openssh-5.5p1/sshconnect2.c.fips openssh-5.5p1/sshconnect2.c ---- openssh-5.5p1/sshconnect2.c.fips 2010-04-16 08:46:48.000000000 +0200 -+++ openssh-5.5p1/sshconnect2.c 2010-04-16 08:46:49.000000000 +0200 -@@ -44,6 +44,8 @@ - #include - #endif - -+#include -+ - #include "openbsd-compat/sys-queue.h" - - #include "xmalloc.h" -@@ -116,6 +118,10 @@ ssh_kex2(char *host, struct sockaddr *ho - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = -+ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; -+ - } - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -131,7 +137,11 @@ ssh_kex2(char *host, struct sockaddr *ho - if (options.macs != NULL) { - myproposal[PROPOSAL_MAC_ALGS_CTOS] = - myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_MAC_ALGS_CTOS] = -+ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; - } -+ - if (options.hostkeyalgorithms != NULL) - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = - options.hostkeyalgorithms; -@@ -529,8 +539,8 @@ input_userauth_pk_ok(int type, u_int32_t - key->type, pktype); - goto done; - } -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- debug2("input_userauth_pk_ok: fp %s", fp); -+ fp = key_fingerprint(key, SSH_FP_SHA1, SSH_FP_HEX); -+ debug2("input_userauth_pk_ok: SHA1 fp %s", fp); - xfree(fp); - - /* -diff -up openssh-5.5p1/sshconnect.c.fips openssh-5.5p1/sshconnect.c ---- openssh-5.5p1/sshconnect.c.fips 2010-03-04 11:53:36.000000000 +0100 -+++ openssh-5.5p1/sshconnect.c 2010-04-16 08:46:49.000000000 +0200 -@@ -40,6 +40,8 @@ - #include - #include - -+#include -+ - #include "xmalloc.h" - #include "key.h" - #include "hostfile.h" -@@ -789,6 +791,7 @@ check_host_key(char *hostname, struct so - goto fail; - } else if (options.strict_host_key_checking == 2) { - char msg1[1024], msg2[1024]; -+ int fips_on = FIPS_mode(); - - if (show_other_keys(host, host_key)) - snprintf(msg1, sizeof(msg1), -@@ -797,8 +800,8 @@ check_host_key(char *hostname, struct so - else - snprintf(msg1, sizeof(msg1), "."); - /* The default */ -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(host_key, SSH_FP_MD5, -+ fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); -+ ra = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, - SSH_FP_RANDOMART); - msg2[0] = '\0'; - if (options.verify_host_key_dns) { -@@ -814,10 +817,10 @@ check_host_key(char *hostname, struct so - snprintf(msg, sizeof(msg), - "The authenticity of host '%.200s (%s)' can't be " - "established%s\n" -- "%s key fingerprint is %s.%s%s\n%s" -+ "%s key %sfingerprint is %s.%s%s\n%s" - "Are you sure you want to continue connecting " - "(yes/no)? ", -- host, ip, msg1, type, fp, -+ host, ip, msg1, type, fips_on ? "SHA1 " : "", fp, - options.visual_host_key ? "\n" : "", - options.visual_host_key ? ra : "", - msg2); -@@ -1151,17 +1154,18 @@ show_key_from_file(const char *file, con - Key *found; - char *fp, *ra; - int line, ret; -+ int fips_on = FIPS_mode(); - - found = key_new(keytype); - if ((ret = lookup_key_in_hostfile_by_type(file, host, - keytype, found, &line))) { -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART); -+ fp = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); -+ ra = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_RANDOMART); - logit("WARNING: %s key found for host %s\n" - "in %s:%d\n" -- "%s key fingerprint %s.\n%s\n", -+ "%s key %sfingerprint %s.\n%s\n", - key_type(found), host, file, line, -- key_type(found), fp, ra); -+ key_type(found), fips_on ? "SHA1 ":"", fp, ra); - xfree(ra); - xfree(fp); - } -@@ -1207,8 +1211,9 @@ warn_changed_key(Key *host_key) - { - char *fp; - const char *type = key_type(host_key); -+ int fips_on = FIPS_mode(); - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); - - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); -@@ -1216,8 +1221,8 @@ warn_changed_key(Key *host_key) - error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); - error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); - error("It is also possible that the %s host key has just been changed.", type); -- error("The fingerprint for the %s key sent by the remote host is\n%s.", -- type, fp); -+ error("The %sfingerprint for the %s key sent by the remote host is\n%s.", -+ fips_on ? "SHA1 ":"", type, fp); - error("Please contact your system administrator."); - - xfree(fp); -diff -up openssh-5.5p1/sshd.c.fips openssh-5.5p1/sshd.c ---- openssh-5.5p1/sshd.c.fips 2010-04-16 08:46:48.000000000 +0200 -+++ openssh-5.5p1/sshd.c 2010-04-16 08:46:49.000000000 +0200 -@@ -76,6 +76,8 @@ - #include - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - - #ifdef HAVE_SECUREWARE -@@ -1298,6 +1300,12 @@ main(int ac, char **av) - (void)set_auth_parameters(ac, av); - #endif - __progname = ssh_get_progname(av[0]); -+ -+ SSLeay_add_all_algorithms(); -+ if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) { -+ fatal("FIPS integrity verification test failed."); -+ } -+ - init_rng(); - - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ -@@ -1459,8 +1467,6 @@ main(int ac, char **av) - else - closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); - -- SSLeay_add_all_algorithms(); -- - /* - * Force logging to stderr until we have loaded the private host - * key (unless started from inetd) -@@ -1578,6 +1584,10 @@ main(int ac, char **av) - debug("private host key: #%d type %d %s", i, key->type, - key_type(key)); - } -+ if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) { -+ logit("Disabling protocol version 1. Not allowed in the FIPS mode."); -+ options.protocol &= ~SSH_PROTO_1; -+ } - if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { - logit("Disabling protocol version 1. Could not load host key"); - options.protocol &= ~SSH_PROTO_1; -@@ -1742,6 +1752,10 @@ main(int ac, char **av) - /* Initialize the random number generator. */ - arc4random_stir(); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - /* Chdir to the root directory so that the current disk can be - unmounted if desired. */ - chdir("/"); -@@ -2275,6 +2289,9 @@ do_ssh2_kex(void) - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = -+ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; - } - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -2284,6 +2301,9 @@ do_ssh2_kex(void) - if (options.macs != NULL) { - myproposal[PROPOSAL_MAC_ALGS_CTOS] = - myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_MAC_ALGS_CTOS] = -+ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; - } - if (options.compression == COMP_NONE) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = -diff -up openssh-5.5p1/ssh-keygen.c.fips openssh-5.5p1/ssh-keygen.c ---- openssh-5.5p1/ssh-keygen.c.fips 2010-03-21 19:58:24.000000000 +0100 -+++ openssh-5.5p1/ssh-keygen.c 2010-04-16 08:46:49.000000000 +0200 -@@ -21,6 +21,7 @@ - - #include - #include -+#include - #include "openbsd-compat/openssl-compat.h" - - #include -@@ -527,7 +528,7 @@ do_fingerprint(struct passwd *pw) - enum fp_type fptype; - struct stat st; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5; - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; - - if (!have_identity) -@@ -1916,14 +1917,15 @@ passphrase_again: - fclose(f); - - if (!quiet) { -- char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); -- char *ra = key_fingerprint(public, SSH_FP_MD5, -+ int fips_on = FIPS_mode(); -+ char *fp = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); -+ char *ra = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, - SSH_FP_RANDOMART); - printf("Your public key has been saved in %s.\n", - identity_file); -- printf("The key fingerprint is:\n"); -+ printf("The key %sfingerprint is:\n", fips_on ? "SHA1 " : ""); - printf("%s %s\n", fp, comment); -- printf("The key's randomart image is:\n"); -+ printf("The key's %srandomart image is:\n", fips_on ? "SHA1 " :""); - printf("%s\n", ra); - xfree(ra); - xfree(fp); diff --git a/openssh-5.5p1-gsskex.patch b/openssh-5.5p1-gsskex.patch deleted file mode 100644 index 249faa4..0000000 --- a/openssh-5.5p1-gsskex.patch +++ /dev/null @@ -1,2933 +0,0 @@ -diff -up openssh-5.5p1/auth2.c.gsskex openssh-5.5p1/auth2.c ---- openssh-5.5p1/auth2.c.gsskex 2010-05-13 15:59:50.000000000 +0200 -+++ openssh-5.5p1/auth2.c 2010-05-13 15:59:58.000000000 +0200 -@@ -69,6 +69,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - #ifdef JPAKE -@@ -79,6 +80,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - #ifdef JPAKE -@@ -289,6 +291,7 @@ input_userauth_request(int type, u_int32 - #endif - - authctxt->postponed = 0; -+ authctxt->server_caused_failure = 0; - - /* try to authenticate user */ - m = authmethod_lookup(method); -@@ -361,7 +364,8 @@ userauth_finish(Authctxt *authctxt, int - } else { - - /* Allow initial try of "none" auth without failure penalty */ -- if (authctxt->attempt > 1 || strcmp(method, "none") != 0) -+ if (!authctxt->server_caused_failure && -+ (authctxt->attempt > 1 || strcmp(method, "none") != 0)) - authctxt->failures++; - if (authctxt->failures >= options.max_authtries) { - #ifdef SSH_AUDIT_EVENTS -diff -up openssh-5.5p1/auth2-gss.c.gsskex openssh-5.5p1/auth2-gss.c ---- openssh-5.5p1/auth2-gss.c.gsskex 2010-05-13 15:59:50.000000000 +0200 -+++ openssh-5.5p1/auth2-gss.c 2010-05-13 15:59:58.000000000 +0200 -@@ -1,7 +1,7 @@ - /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u - static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); - static void input_gssapi_errtok(int, u_int32_t, void *); - -+/* -+ * The 'gssapi_keyex' userauth mechanism. -+ */ -+static int -+userauth_gsskeyex(Authctxt *authctxt) -+{ -+ int authenticated = 0; -+ Buffer b; -+ gss_buffer_desc mic, gssbuf; -+ u_int len; -+ -+ mic.value = packet_get_string(&len); -+ mic.length = len; -+ -+ packet_check_eom(); -+ -+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, -+ "gssapi-keyex"); -+ -+ gssbuf.value = buffer_ptr(&b); -+ gssbuf.length = buffer_len(&b); -+ -+ /* gss_kex_context is NULL with privsep, so we can't check it here */ -+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf, &mic)))) -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw)); -+ -+ buffer_free(&b); -+ xfree(mic.value); -+ -+ return (authenticated); -+} -+ - /* - * We only support those mechanisms that we know about (ie ones that we know - * how to check local user kuserok and the like) -@@ -102,6 +136,7 @@ userauth_gssapi(Authctxt *authctxt) - - if (!present) { - xfree(doid); -+ authctxt->server_caused_failure = 1; - return (0); - } - -@@ -109,6 +144,7 @@ userauth_gssapi(Authctxt *authctxt) - if (ctxt != NULL) - ssh_gssapi_delete_ctx(&ctxt); - xfree(doid); -+ authctxt->server_caused_failure = 1; - return (0); - } - -@@ -242,7 +278,8 @@ input_gssapi_exchange_complete(int type, - - packet_check_eom(); - -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw)); - - authctxt->postponed = 0; - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); -@@ -284,7 +321,8 @@ input_gssapi_mic(int type, u_int32_t ple - gssbuf.length = buffer_len(&b); - - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); - else - logit("GSSAPI MIC check failed"); - -@@ -301,6 +339,12 @@ input_gssapi_mic(int type, u_int32_t ple - userauth_finish(authctxt, authenticated, "gssapi-with-mic"); - } - -+Authmethod method_gsskeyex = { -+ "gssapi-keyex", -+ userauth_gsskeyex, -+ &options.gss_authentication -+}; -+ - Authmethod method_gssapi = { - "gssapi-with-mic", - userauth_gssapi, -diff -up openssh-5.5p1/auth.h.gsskex openssh-5.5p1/auth.h ---- openssh-5.5p1/auth.h.gsskex 2010-05-13 15:59:50.000000000 +0200 -+++ openssh-5.5p1/auth.h 2010-05-13 15:59:58.000000000 +0200 -@@ -53,6 +53,7 @@ struct Authctxt { - int valid; /* user exists and is allowed to login */ - int attempt; - int failures; -+ int server_caused_failure; - int force_pwchange; - char *user; /* username sent by the client */ - char *service; -diff -up openssh-5.5p1/auth-krb5.c.gsskex openssh-5.5p1/auth-krb5.c ---- openssh-5.5p1/auth-krb5.c.gsskex 2009-12-21 00:49:22.000000000 +0100 -+++ openssh-5.5p1/auth-krb5.c 2010-05-13 15:59:58.000000000 +0200 -@@ -170,8 +170,13 @@ auth_krb5_password(Authctxt *authctxt, c - - len = strlen(authctxt->krb5_ticket_file) + 6; - authctxt->krb5_ccname = xmalloc(len); -+#ifdef USE_CCAPI -+ snprintf(authctxt->krb5_ccname, len, "API:%s", -+ authctxt->krb5_ticket_file); -+#else - snprintf(authctxt->krb5_ccname, len, "FILE:%s", - authctxt->krb5_ticket_file); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -226,15 +231,22 @@ krb5_cleanup_proc(Authctxt *authctxt) - #ifndef HEIMDAL - krb5_error_code - ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { -- int tmpfd, ret; -+ int ret; - char ccname[40]; - mode_t old_umask; -+#ifdef USE_CCAPI -+ char cctemplate[] = "API:krb5cc_%d"; -+#else -+ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; -+ int tmpfd; -+#endif - - ret = snprintf(ccname, sizeof(ccname), -- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); -+ cctemplate, geteuid()); - if (ret < 0 || (size_t)ret >= sizeof(ccname)) - return ENOMEM; - -+#ifndef USE_CCAPI - old_umask = umask(0177); - tmpfd = mkstemp(ccname + strlen("FILE:")); - umask(old_umask); -@@ -249,6 +261,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c - return errno; - } - close(tmpfd); -+#endif - - return (krb5_cc_resolve(ctx, ccname, ccache)); - } -diff -up openssh-5.5p1/ChangeLog.gssapi.gsskex openssh-5.5p1/ChangeLog.gssapi ---- openssh-5.5p1/ChangeLog.gssapi.gsskex 2010-05-13 15:59:58.000000000 +0200 -+++ openssh-5.5p1/ChangeLog.gssapi 2010-05-13 15:59:58.000000000 +0200 -@@ -0,0 +1,95 @@ -+20090615 -+ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c -+ sshd.c ] -+ Fix issues identified by Greg Hudson following a code review -+ Check return value of gss_indicate_mechs -+ Protect GSSAPI calls in monitor, so they can only be used if enabled -+ Check return values of bignum functions in key exchange -+ Use BN_clear_free to clear other side's DH value -+ Make ssh_gssapi_id_kex more robust -+ Only configure kex table pointers if GSSAPI is enabled -+ Don't leak mechanism list, or gss mechanism list -+ Cast data.length before printing -+ If serverkey isn't provided, use an empty string, rather than NULL -+ -+20090201 -+ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h -+ ssh_config.5 sshconnet2.c ] -+ Add support for the GSSAPIClientIdentity option, which allows the user -+ to specify which GSSAPI identity to use to contact a given server -+ -+20080404 -+ - [ gss-serv.c ] -+ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow -+ been omitted from a previous version of this patch. Reported by Borislav -+ Stoichkov -+ -+20070317 -+ - [ gss-serv-krb5.c ] -+ Remove C99ism, where new_ccname was being declared in the middle of a -+ function -+ -+20061220 -+ - [ servconf.c ] -+ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and -+ documented, behaviour. Reported by Dan Watson. -+ -+20060910 -+ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c -+ ssh-gss.h ] -+ add support for gss-group14-sha1 key exchange mechanisms -+ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] -+ Add GSSAPIStrictAcceptorCheck option to allow the disabling of -+ acceptor principal checking on multi-homed machines. -+ -+ - [ sshd_config ssh_config ] -+ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample -+ configuration files -+ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] -+ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() -+ Limit length of error messages displayed by client -+ -+20060909 -+ - [ gss-genr.c gss-serv.c ] -+ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server -+ only, where they belong -+ -+ -+20060829 -+ - [ gss-serv-krb5.c ] -+ Fix CCAPI credentials cache name when creating KRB5CCNAME environment -+ variable -+ -+20060828 -+ - [ gss-genr.c ] -+ Avoid Heimdal context freeing problem -+ -+ -+20060818 -+ - [ gss-genr.c ssh-gss.h sshconnect2.c ] -+ Make sure that SPENGO is disabled -+ -+ -+20060421 -+ - [ gssgenr.c, sshconnect2.c ] -+ a few type changes (signed versus unsigned, int versus size_t) to -+ fix compiler errors/warnings -+ (from jbasney AT ncsa.uiuc.edu) -+ - [ kexgssc.c, sshconnect2.c ] -+ fix uninitialized variable warnings -+ (from jbasney AT ncsa.uiuc.edu) -+ - [ gssgenr.c ] -+ pass oid to gss_display_status (helpful when using GSSAPI mechglue) -+ (from jbasney AT ncsa.uiuc.edu) -+ -+ - [ gss-serv-krb5.c ] -+ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H -+ (from jbasney AT ncsa.uiuc.edu) -+ -+ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c -+ add client-side GssapiKeyExchange option -+ (from jbasney AT ncsa.uiuc.edu) -+ - [ sshconnect2.c ] -+ add support for GssapiTrustDns option for gssapi-with-mic -+ (from jbasney AT ncsa.uiuc.edu) -+ -diff -up openssh-5.5p1/clientloop.c.gsskex openssh-5.5p1/clientloop.c ---- openssh-5.5p1/clientloop.c.gsskex 2010-03-21 19:54:02.000000000 +0100 -+++ openssh-5.5p1/clientloop.c 2010-05-13 15:59:58.000000000 +0200 -@@ -111,6 +111,10 @@ - #include "msg.h" - #include "roaming.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* import options */ - extern Options options; - -@@ -1431,6 +1435,13 @@ client_loop(int have_pty, int escape_cha - /* Do channel operations unless rekeying in progress. */ - if (!rekeying) { - channel_after_select(readset, writeset); -+ -+ if (options.gss_renewal_rekey && -+ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) { -+ debug("credentials updated - forcing rekey"); -+ need_rekeying = 1; -+ } -+ - if (need_rekeying || packet_need_rekeying()) { - debug("need rekeying"); - xxx_kex->done = 0; -diff -up openssh-5.5p1/configure.ac.gsskex openssh-5.5p1/configure.ac ---- openssh-5.5p1/configure.ac.gsskex 2010-05-13 15:59:52.000000000 +0200 -+++ openssh-5.5p1/configure.ac 2010-05-13 15:59:58.000000000 +0200 -@@ -477,6 +477,30 @@ main() { if (NSVersionOfRunTimeLibrary(" - [Use tunnel device compatibility to OpenBSD]) - AC_DEFINE(SSH_TUN_PREPEND_AF, 1, - [Prepend the address family to IP tunnel traffic]) -+ AC_MSG_CHECKING(if we have the Security Authorization Session API) -+ AC_TRY_COMPILE([#include ], -+ [SessionCreate(0, 0);], -+ [ac_cv_use_security_session_api="yes" -+ AC_DEFINE(USE_SECURITY_SESSION_API, 1, -+ [platform has the Security Authorization Session API]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT(yes)], -+ [ac_cv_use_security_session_api="no" -+ AC_MSG_RESULT(no)]) -+ AC_MSG_CHECKING(if we have an in-memory credentials cache) -+ AC_TRY_COMPILE( -+ [#include ], -+ [cc_context_t c; -+ (void) cc_initialize (&c, 0, NULL, NULL);], -+ [AC_DEFINE(USE_CCAPI, 1, -+ [platform uses an in-memory credentials cache]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT(yes) -+ if test "x$ac_cv_use_security_session_api" = "xno"; then -+ AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) -+ fi], -+ [AC_MSG_RESULT(no)] -+ ) - m4_pattern_allow(AU_IPv) - AC_CHECK_DECL(AU_IPv4, [], - AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) -diff -up openssh-5.5p1/gss-genr.c.gsskex openssh-5.5p1/gss-genr.c ---- openssh-5.5p1/gss-genr.c.gsskex 2009-06-22 08:11:07.000000000 +0200 -+++ openssh-5.5p1/gss-genr.c 2010-05-13 15:59:58.000000000 +0200 -@@ -39,12 +39,167 @@ - #include "buffer.h" - #include "log.h" - #include "ssh2.h" -+#include "cipher.h" -+#include "key.h" -+#include "kex.h" -+#include - - #include "ssh-gss.h" - - extern u_char *session_id2; - extern u_int session_id2_len; - -+typedef struct { -+ char *encoded; -+ gss_OID oid; -+} ssh_gss_kex_mapping; -+ -+/* -+ * XXX - It would be nice to find a more elegant way of handling the -+ * XXX passing of the key exchange context to the userauth routines -+ */ -+ -+Gssctxt *gss_kex_context = NULL; -+ -+static ssh_gss_kex_mapping *gss_enc2oid = NULL; -+ -+int -+ssh_gssapi_oid_table_ok() { -+ return (gss_enc2oid != NULL); -+} -+ -+/* -+ * Return a list of the gss-group1-sha1 mechanisms supported by this program -+ * -+ * We test mechanisms to ensure that we can use them, to avoid starting -+ * a key exchange with a bad mechanism -+ */ -+ -+char * -+ssh_gssapi_client_mechanisms(const char *host, const char *client) { -+ gss_OID_set gss_supported; -+ OM_uint32 min_status; -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) -+ return NULL; -+ -+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, -+ host, client)); -+} -+ -+char * -+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, -+ const char *host, const char *client) { -+ Buffer buf; -+ size_t i; -+ int oidpos, enclen; -+ char *mechs, *encoded; -+ u_char digest[EVP_MAX_MD_SIZE]; -+ char deroid[2]; -+ const EVP_MD *evp_md = EVP_md5(); -+ EVP_MD_CTX md; -+ -+ if (gss_enc2oid != NULL) { -+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++) -+ xfree(gss_enc2oid[i].encoded); -+ xfree(gss_enc2oid); -+ } -+ -+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * -+ (gss_supported->count + 1)); -+ -+ buffer_init(&buf); -+ -+ oidpos = 0; -+ for (i = 0; i < gss_supported->count; i++) { -+ if (gss_supported->elements[i].length < 128 && -+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) { -+ -+ deroid[0] = SSH_GSS_OIDTYPE; -+ deroid[1] = gss_supported->elements[i].length; -+ -+ EVP_DigestInit(&md, evp_md); -+ EVP_DigestUpdate(&md, deroid, 2); -+ EVP_DigestUpdate(&md, -+ gss_supported->elements[i].elements, -+ gss_supported->elements[i].length); -+ EVP_DigestFinal(&md, digest, NULL); -+ -+ encoded = xmalloc(EVP_MD_size(evp_md) * 2); -+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md), -+ encoded, EVP_MD_size(evp_md) * 2); -+ -+ if (oidpos != 0) -+ buffer_put_char(&buf, ','); -+ -+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, -+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ buffer_put_char(&buf, ','); -+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, -+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ buffer_put_char(&buf, ','); -+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, -+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ -+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); -+ gss_enc2oid[oidpos].encoded = encoded; -+ oidpos++; -+ } -+ } -+ gss_enc2oid[oidpos].oid = NULL; -+ gss_enc2oid[oidpos].encoded = NULL; -+ -+ buffer_put_char(&buf, '\0'); -+ -+ mechs = xmalloc(buffer_len(&buf)); -+ buffer_get(&buf, mechs, buffer_len(&buf)); -+ buffer_free(&buf); -+ -+ if (strlen(mechs) == 0) { -+ xfree(mechs); -+ mechs = NULL; -+ } -+ -+ return (mechs); -+} -+ -+gss_OID -+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { -+ int i = 0; -+ -+ switch (kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; -+ break; -+ case KEX_GSS_GEX_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; -+ break; -+ default: -+ return GSS_C_NO_OID; -+ } -+ -+ while (gss_enc2oid[i].encoded != NULL && -+ strcmp(name, gss_enc2oid[i].encoded) != 0) -+ i++; -+ -+ if (gss_enc2oid[i].oid != NULL && ctx != NULL) -+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); -+ -+ return gss_enc2oid[i].oid; -+} -+ - /* Check that the OID in a data stream matches that in the context */ - int - ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) -@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de - } - - ctx->major = gss_init_sec_context(&ctx->minor, -- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, -+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid, - GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, - 0, NULL, recv_tok, NULL, send_tok, flags, NULL); - -@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con - } - - OM_uint32 -+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) -+{ -+ gss_buffer_desc gssbuf; -+ gss_name_t gssname; -+ OM_uint32 status; -+ gss_OID_set oidset; -+ -+ gssbuf.value = (void *) name; -+ gssbuf.length = strlen(gssbuf.value); -+ -+ gss_create_empty_oid_set(&status, &oidset); -+ gss_add_oid_set_member(&status, ctx->oid, &oidset); -+ -+ ctx->major = gss_import_name(&ctx->minor, &gssbuf, -+ GSS_C_NT_USER_NAME, &gssname); -+ -+ if (!ctx->major) -+ ctx->major = gss_acquire_cred(&ctx->minor, -+ gssname, 0, oidset, GSS_C_INITIATE, -+ &ctx->client_creds, NULL, NULL); -+ -+ gss_release_name(&status, &gssname); -+ gss_release_oid_set(&status, &oidset); -+ -+ if (ctx->major) -+ ssh_gssapi_error(ctx); -+ -+ return(ctx->major); -+} -+ -+OM_uint32 - ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) - { -+ if (ctx == NULL) -+ return -1; -+ - if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, - GSS_C_QOP_DEFAULT, buffer, hash))) - ssh_gssapi_error(ctx); -@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer - return (ctx->major); - } - -+/* Priviledged when used by server */ -+OM_uint32 -+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+{ -+ if (ctx == NULL) -+ return -1; -+ -+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -+ gssbuf, gssmic, NULL); -+ -+ return (ctx->major); -+} -+ - void - ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, - const char *context) -@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha - } - - int --ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) -+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, -+ const char *client) - { - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - OM_uint32 major, minor; - gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; -+ Gssctxt *intctx = NULL; -+ -+ if (ctx == NULL) -+ ctx = &intctx; - - /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx - ssh_gssapi_build_ctx(ctx); - ssh_gssapi_set_oid(*ctx, oid); - major = ssh_gssapi_import_name(*ctx, host); -+ -+ if (!GSS_ERROR(major) && client) -+ major = ssh_gssapi_client_identity(*ctx, client); -+ - if (!GSS_ERROR(major)) { - major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, - NULL); -@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx - GSS_C_NO_BUFFER); - } - -- if (GSS_ERROR(major)) -+ if (GSS_ERROR(major) || intctx != NULL) - ssh_gssapi_delete_ctx(ctx); - - return (!GSS_ERROR(major)); - } - -+int -+ssh_gssapi_credentials_updated(Gssctxt *ctxt) { -+ static gss_name_t saved_name = GSS_C_NO_NAME; -+ static OM_uint32 saved_lifetime = 0; -+ static gss_OID saved_mech = GSS_C_NO_OID; -+ static gss_name_t name; -+ static OM_uint32 last_call = 0; -+ OM_uint32 lifetime, now, major, minor; -+ int equal; -+ gss_cred_usage_t usage = GSS_C_INITIATE; -+ -+ now = time(NULL); -+ -+ if (ctxt) { -+ debug("Rekey has happened - updating saved versions"); -+ -+ if (saved_name != GSS_C_NO_NAME) -+ gss_release_name(&minor, &saved_name); -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &saved_name, &saved_lifetime, NULL, NULL); -+ -+ if (!GSS_ERROR(major)) { -+ saved_mech = ctxt->oid; -+ saved_lifetime+= now; -+ } else { -+ /* Handle the error */ -+ } -+ return 0; -+ } -+ -+ if (now - last_call < 10) -+ return 0; -+ -+ last_call = now; -+ -+ if (saved_mech == GSS_C_NO_OID) -+ return 0; -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &name, &lifetime, NULL, NULL); -+ if (major == GSS_S_CREDENTIALS_EXPIRED) -+ return 0; -+ else if (GSS_ERROR(major)) -+ return 0; -+ -+ major = gss_compare_name(&minor, saved_name, name, &equal); -+ gss_release_name(&minor, &name); -+ if (GSS_ERROR(major)) -+ return 0; -+ -+ if (equal && (saved_lifetime < lifetime + now - 10)) -+ return 1; -+ -+ return 0; -+} -+ - #endif /* GSSAPI */ -diff -up openssh-5.5p1/gss-serv.c.gsskex openssh-5.5p1/gss-serv.c ---- openssh-5.5p1/gss-serv.c.gsskex 2008-05-19 07:05:07.000000000 +0200 -+++ openssh-5.5p1/gss-serv.c 2010-05-13 15:59:58.000000000 +0200 -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -45,15 +45,20 @@ - #include "channels.h" - #include "session.h" - #include "misc.h" -+#include "servconf.h" -+#include "uidswap.h" - - #include "ssh-gss.h" -+#include "monitor_wrap.h" -+ -+extern ServerOptions options; - - static ssh_gssapi_client gssapi_client = - { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, -- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; -+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; - - ssh_gssapi_mech gssapi_null_mech = -- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; -+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; - - #ifdef KRB5 - extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) - char lname[MAXHOSTNAMELEN]; - gss_OID_set oidset; - -- gss_create_empty_oid_set(&status, &oidset); -- gss_add_oid_set_member(&status, ctx->oid, &oidset); -+ if (options.gss_strict_acceptor) { -+ gss_create_empty_oid_set(&status, &oidset); -+ gss_add_oid_set_member(&status, ctx->oid, &oidset); -+ -+ if (gethostname(lname, MAXHOSTNAMELEN)) { -+ gss_release_oid_set(&status, &oidset); -+ return (-1); -+ } - -- if (gethostname(lname, MAXHOSTNAMELEN)) { -- gss_release_oid_set(&status, &oidset); -- return (-1); -- } -+ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { -+ gss_release_oid_set(&status, &oidset); -+ return (ctx->major); -+ } -+ -+ if ((ctx->major = gss_acquire_cred(&ctx->minor, -+ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, -+ NULL, NULL))) -+ ssh_gssapi_error(ctx); - -- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { - gss_release_oid_set(&status, &oidset); - return (ctx->major); -+ } else { -+ ctx->name = GSS_C_NO_NAME; -+ ctx->creds = GSS_C_NO_CREDENTIAL; - } -- -- if ((ctx->major = gss_acquire_cred(&ctx->minor, -- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) -- ssh_gssapi_error(ctx); -- -- gss_release_oid_set(&status, &oidset); -- return (ctx->major); -+ return GSS_S_COMPLETE; - } - - /* Privileged */ -@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss - } - - /* Unprivileged */ -+char * -+ssh_gssapi_server_mechanisms() { -+ gss_OID_set supported; -+ -+ ssh_gssapi_supported_oids(&supported); -+ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, -+ NULL, NULL)); -+} -+ -+/* Unprivileged */ -+int -+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, -+ const char *dummy) { -+ Gssctxt *ctx = NULL; -+ int res; -+ -+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); -+ ssh_gssapi_delete_ctx(&ctx); -+ -+ return (res); -+} -+ -+/* Unprivileged */ - void - ssh_gssapi_supported_oids(gss_OID_set *oidset) - { -@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o - gss_OID_set supported; - - gss_create_empty_oid_set(&min_status, oidset); -- gss_indicate_mechs(&min_status, &supported); -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) -+ return; - - while (supported_mechs[i]->name != NULL) { - if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -247,8 +284,48 @@ OM_uint32 - ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - { - int i = 0; -+ int equal = 0; -+ gss_name_t new_name = GSS_C_NO_NAME; -+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; -+ -+ if (options.gss_store_rekey && client->used && ctx->client_creds) { -+ if (client->mech->oid.length != ctx->oid->length || -+ (memcmp(client->mech->oid.elements, -+ ctx->oid->elements, ctx->oid->length) !=0)) { -+ debug("Rekeyed credentials have different mechanism"); -+ return GSS_S_COMPLETE; -+ } -+ -+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &new_name, -+ NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ ctx->major = gss_compare_name(&ctx->minor, client->name, -+ new_name, &equal); - -- gss_buffer_desc ename; -+ if (GSS_ERROR(ctx->major)) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ if (!equal) { -+ debug("Rekeyed credentials have different name"); -+ return GSS_S_COMPLETE; -+ } -+ -+ debug("Marking rekeyed credentials for export"); -+ -+ gss_release_name(&ctx->minor, &client->name); -+ gss_release_cred(&ctx->minor, &client->creds); -+ client->name = new_name; -+ client->creds = ctx->client_creds; -+ ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ client->updated = 1; -+ return GSS_S_COMPLETE; -+ } - - client->mech = NULL; - -@@ -263,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ if (ctx->client_creds && -+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ - if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, - &client->displayname, NULL))) { - ssh_gssapi_error(ctx); -@@ -280,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - return (ctx->major); - } - -+ gss_release_buffer(&ctx->minor, &ename); -+ - /* We can't copy this structure, so we just move the pointer to it */ - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; -@@ -327,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int - - /* Privileged */ - int --ssh_gssapi_userok(char *user) -+ssh_gssapi_userok(char *user, struct passwd *pw) - { - OM_uint32 lmin; - -@@ -337,9 +423,11 @@ ssh_gssapi_userok(char *user) - return 0; - } - if (gssapi_client.mech && gssapi_client.mech->userok) -- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) -+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { -+ gssapi_client.used = 1; -+ gssapi_client.store.owner = pw; - return 1; -- else { -+ } else { - /* Destroy delegated credentials if userok fails */ - gss_release_buffer(&lmin, &gssapi_client.displayname); - gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -352,14 +440,90 @@ ssh_gssapi_userok(char *user) - return (0); - } - --/* Privileged */ --OM_uint32 --ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+/* These bits are only used for rekeying. The unpriviledged child is running -+ * as the user, the monitor is root. -+ * -+ * In the child, we want to : -+ * *) Ask the monitor to store our credentials into the store we specify -+ * *) If it succeeds, maybe do a PAM update -+ */ -+ -+/* Stuff for PAM */ -+ -+#ifdef USE_PAM -+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, -+ struct pam_response **resp, void *data) - { -- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -- gssbuf, gssmic, NULL); -+ return (PAM_CONV_ERR); -+} -+#endif - -- return (ctx->major); -+void -+ssh_gssapi_rekey_creds() { -+ int ok; -+ int ret; -+#ifdef USE_PAM -+ pam_handle_t *pamh = NULL; -+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; -+ char *envstr; -+#endif -+ -+ if (gssapi_client.store.filename == NULL && -+ gssapi_client.store.envval == NULL && -+ gssapi_client.store.envvar == NULL) -+ return; -+ -+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -+ -+ if (!ok) -+ return; -+ -+ debug("Rekeyed credentials stored successfully"); -+ -+ /* Actually managing to play with the ssh pam stack from here will -+ * be next to impossible. In any case, we may want different options -+ * for rekeying. So, use our own :) -+ */ -+#ifdef USE_PAM -+ if (!use_privsep) { -+ debug("Not even going to try and do PAM with privsep disabled"); -+ return; -+ } -+ -+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, -+ &pamconv, &pamh); -+ if (ret) -+ return; -+ -+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, -+ gssapi_client.store.envval); -+ -+ ret = pam_putenv(pamh, envstr); -+ if (!ret) -+ pam_setcred(pamh, PAM_REINITIALIZE_CRED); -+ pam_end(pamh, PAM_SUCCESS); -+#endif -+} -+ -+int -+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { -+ int ok = 0; -+ -+ /* Check we've got credentials to store */ -+ if (!gssapi_client.updated) -+ return 0; -+ -+ gssapi_client.updated = 0; -+ -+ temporarily_use_uid(gssapi_client.store.owner); -+ if (gssapi_client.mech && gssapi_client.mech->updatecreds) -+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); -+ else -+ debug("No update function for this mechanism"); -+ -+ restore_uid(); -+ -+ return ok; - } - - #endif -diff -up openssh-5.5p1/gss-serv-krb5.c.gsskex openssh-5.5p1/gss-serv-krb5.c ---- openssh-5.5p1/gss-serv-krb5.c.gsskex 2006-09-01 07:38:36.000000000 +0200 -+++ openssh-5.5p1/gss-serv-krb5.c 2010-05-13 15:59:59.000000000 +0200 -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - krb5_principal princ; - OM_uint32 maj_status, min_status; - int len; -+ const char *new_ccname; - - if (client->creds == NULL) { - debug("No credentials stored"); -@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_ccname = krb5_cc_get_name(krb_context, ccache); -+ - client->store.envvar = "KRB5CCNAME"; -- len = strlen(client->store.filename) + 6; -- client->store.envval = xmalloc(len); -- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); -+#ifdef USE_CCAPI -+ xasprintf(&client->store.envval, "API:%s", new_ccname); -+ client->store.filename = NULL; -+#else -+ xasprintf(&client->store.envval, "FILE:%s", new_ccname); -+ client->store.filename = xstrdup(new_ccname); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - return; - } - -+int -+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client) -+{ -+ krb5_ccache ccache = NULL; -+ krb5_principal principal = NULL; -+ char *name = NULL; -+ krb5_error_code problem; -+ OM_uint32 maj_status, min_status; -+ -+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { -+ logit("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ return 0; -+ } -+ -+ /* Find out who the principal in this cache is */ -+ if ((problem = krb5_cc_get_principal(krb_context, ccache, -+ &principal))) { -+ logit("krb5_cc_get_principal(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { -+ logit("krb5_unparse_name(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ -+ if (strcmp(name,client->exportedname.value)!=0) { -+ debug("Name in local credentials cache differs. Not storing"); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ krb5_free_unparsed_name(krb_context, name); -+ return 0; -+ } -+ krb5_free_unparsed_name(krb_context, name); -+ -+ /* Name matches, so lets get on with it! */ -+ -+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { -+ logit("krb5_cc_initialize(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ krb5_free_principal(krb_context, principal); -+ -+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, -+ ccache))) { -+ logit("gss_krb5_copy_ccache() failed. Sorry!"); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ return 1; -+} -+ - ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", -@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { - NULL, - &ssh_gssapi_krb5_userok, - NULL, -- &ssh_gssapi_krb5_storecreds -+ &ssh_gssapi_krb5_storecreds, -+ &ssh_gssapi_krb5_updatecreds - }; - - #endif /* KRB5 */ -diff -up openssh-5.5p1/kex.c.gsskex openssh-5.5p1/kex.c ---- openssh-5.5p1/kex.c.gsskex 2010-01-08 06:50:41.000000000 +0100 -+++ openssh-5.5p1/kex.c 2010-05-13 15:59:59.000000000 +0200 -@@ -50,6 +50,10 @@ - #include "monitor.h" - #include "roaming.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - #if OPENSSL_VERSION_NUMBER >= 0x00907000L - # if defined(HAVE_EVP_SHA256) - # define evp_ssh_sha256 EVP_sha256 -@@ -326,6 +330,20 @@ choose_kex(Kex *k, char *client, char *s - k->kex_type = KEX_DH_GEX_SHA256; - k->evp_md = evp_ssh_sha256(); - #endif -+#ifdef GSSAPI -+ } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, -+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { -+ k->kex_type = KEX_GSS_GEX_SHA1; -+ k->evp_md = EVP_sha1(); -+ } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, -+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { -+ k->kex_type = KEX_GSS_GRP1_SHA1; -+ k->evp_md = EVP_sha1(); -+ } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, -+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { -+ k->kex_type = KEX_GSS_GRP14_SHA1; -+ k->evp_md = EVP_sha1(); -+#endif - } else - fatal("bad kex alg %s", k->name); - } -diff -up openssh-5.5p1/kexgssc.c.gsskex openssh-5.5p1/kexgssc.c ---- openssh-5.5p1/kexgssc.c.gsskex 2010-05-13 15:59:59.000000000 +0200 -+++ openssh-5.5p1/kexgssc.c 2010-05-13 15:59:59.000000000 +0200 -@@ -0,0 +1,334 @@ -+/* -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "includes.h" -+ -+#ifdef GSSAPI -+ -+#include "includes.h" -+ -+#include -+#include -+ -+#include -+ -+#include "xmalloc.h" -+#include "buffer.h" -+#include "ssh2.h" -+#include "key.h" -+#include "cipher.h" -+#include "kex.h" -+#include "log.h" -+#include "packet.h" -+#include "dh.h" -+ -+#include "ssh-gss.h" -+ -+void -+kexgss_client(Kex *kex) { -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ u_int klen, kout, slen = 0, hashlen, strlen; -+ DH *dh; -+ BIGNUM *dh_server_pub = NULL; -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ u_char *kbuf, *hash; -+ u_char *serverhostkey = NULL; -+ u_char *empty = ""; -+ char *msg; -+ char *lang; -+ int type = 0; -+ int first = 1; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); -+ -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); -+ -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ dh = dh_new_group1(); -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ dh = dh_new_group14(); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ debug("Doing group exchange\n"); -+ nbits = dh_estimate(kex->we_need * 8); -+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ); -+ packet_put_int(min); -+ packet_put_int(nbits); -+ packet_put_int(max); -+ -+ packet_send(); -+ -+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP); -+ -+ if ((p = BN_new()) == NULL) -+ fatal("BN_new() failed"); -+ packet_get_bignum2(p); -+ if ((g = BN_new()) == NULL) -+ fatal("BN_new() failed"); -+ packet_get_bignum2(g); -+ packet_check_eom(); -+ -+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) -+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ min, BN_num_bits(p), max); -+ -+ dh = dh_new_group(g, p); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ -+ /* Step 1 - e is dh->pub_key */ -+ dh_gen_key(dh, kex->we_need * 8); -+ -+ /* This is f, we initialise it now to make life easier */ -+ dh_server_pub = BN_new(); -+ if (dh_server_pub == NULL) -+ fatal("dh_server_pub == NULL"); -+ -+ token_ptr = GSS_C_NO_BUFFER; -+ -+ do { -+ debug("Calling gss_init_sec_context"); -+ -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length != 0) { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ xfree(recv_tok.value); -+ -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); -+ -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } -+ -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ packet_start(SSH2_MSG_KEXGSS_INIT); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ packet_put_bignum2(dh->pub_key); -+ first = 0; -+ } else { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ } -+ packet_send(); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = packet_read(); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (serverhostkey) -+ fatal("Server host key received more than once"); -+ serverhostkey = -+ packet_get_string(&slen); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ recv_tok.value = packet_get_string(&strlen); -+ recv_tok.length = strlen; -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ packet_get_bignum2(dh_server_pub); -+ msg_tok.value = packet_get_string(&strlen); -+ msg_tok.length = strlen; -+ -+ /* Is there a token included? */ -+ if (packet_get_char()) { -+ recv_tok.value= -+ packet_get_string(&strlen); -+ recv_tok.length = strlen; -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ packet_disconnect("Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ packet_disconnect("Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ maj_status = packet_get_int(); -+ min_status = packet_get_int(); -+ msg = packet_get_string(NULL); -+ lang = packet_get_string(NULL); -+ fatal("GSSAPI Error: \n%.400s",msg); -+ default: -+ packet_disconnect("Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set dh_server_pub and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* Check f in range [1, p-1] */ -+ if (!dh_pub_is_valid(dh, dh_server_pub)) -+ packet_disconnect("bad server public DH value"); -+ -+ /* compute K=f^x mod p */ -+ klen = DH_size(dh); -+ kbuf = xmalloc(klen); -+ kout = DH_compute_key(kbuf, dh_server_pub, dh); -+ if (kout < 0) -+ fatal("DH_compute_key: failed"); -+ -+ shared_secret = BN_new(); -+ if (shared_secret == NULL) -+ fatal("kexgss_client: BN_new failed"); -+ -+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) -+ fatal("kexdh_client: BN_bin2bn failed"); -+ -+ memset(kbuf, 0, klen); -+ xfree(kbuf); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( kex->client_version_string, -+ kex->server_version_string, -+ buffer_ptr(&kex->my), buffer_len(&kex->my), -+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ dh->pub_key, /* e */ -+ dh_server_pub, /* f */ -+ shared_secret, /* K */ -+ &hash, &hashlen -+ ); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ kexgex_hash( -+ kex->evp_md, -+ kex->client_version_string, -+ kex->server_version_string, -+ buffer_ptr(&kex->my), buffer_len(&kex->my), -+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ min, nbits, max, -+ dh->p, dh->g, -+ dh->pub_key, -+ dh_server_pub, -+ shared_secret, -+ &hash, &hashlen -+ ); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) -+ packet_disconnect("Hash's MIC didn't verify"); -+ -+ xfree(msg_tok.value); -+ -+ DH_free(dh); -+ if (serverhostkey) -+ xfree(serverhostkey); -+ BN_clear_free(dh_server_pub); -+ -+ /* save session id */ -+ if (kex->session_id == NULL) { -+ kex->session_id_len = hashlen; -+ kex->session_id = xmalloc(kex->session_id_len); -+ memcpy(kex->session_id, hash, kex->session_id_len); -+ } -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ kex_derive_keys(kex, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ kex_finish(kex); -+} -+ -+#endif /* GSSAPI */ -diff -up openssh-5.5p1/kexgsss.c.gsskex openssh-5.5p1/kexgsss.c ---- openssh-5.5p1/kexgsss.c.gsskex 2010-05-13 15:59:59.000000000 +0200 -+++ openssh-5.5p1/kexgsss.c 2010-05-13 15:59:59.000000000 +0200 -@@ -0,0 +1,288 @@ -+/* -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "includes.h" -+ -+#ifdef GSSAPI -+ -+#include -+ -+#include -+#include -+ -+#include "xmalloc.h" -+#include "buffer.h" -+#include "ssh2.h" -+#include "key.h" -+#include "cipher.h" -+#include "kex.h" -+#include "log.h" -+#include "packet.h" -+#include "dh.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "servconf.h" -+ -+extern ServerOptions options; -+ -+void -+kexgss_server(Kex *kex) -+{ -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ u_int slen, klen, kout, hashlen; -+ u_char *kbuf, *hash; -+ DH *dh; -+ int min = -1, max = -1, nbits = -1; -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *dh_client_pub = NULL; -+ int type = 0; -+ gss_OID oid; -+ char *mechs; -+ -+ /* Initialise GSSAPI */ -+ -+ /* If we're rekeying, privsep means that some of the private structures -+ * in the GSSAPI code are no longer available. This kludges them back -+ * into life -+ */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ xfree(mechs); -+ -+ debug2("%s: Identifying %s", __func__, kex->name); -+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); -+ if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); -+ -+ debug2("%s: Acquiring credentials", __func__); -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ fatal("Unable to acquire credentials for the server"); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ dh = dh_new_group1(); -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ dh = dh_new_group14(); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ debug("Doing group exchange"); -+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); -+ min = packet_get_int(); -+ nbits = packet_get_int(); -+ max = packet_get_int(); -+ min = MAX(DH_GRP_MIN, min); -+ max = MIN(DH_GRP_MAX, max); -+ packet_check_eom(); -+ if (max < min || nbits < min || max < nbits) -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ dh = PRIVSEP(choose_dh(min, nbits, max)); -+ if (dh == NULL) -+ packet_disconnect("Protocol error: no matching group found"); -+ -+ packet_start(SSH2_MSG_KEXGSS_GROUP); -+ packet_put_bignum2(dh->p); -+ packet_put_bignum2(dh->g); -+ packet_send(); -+ -+ packet_write_wait(); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ -+ dh_gen_key(dh, kex->we_need * 8); -+ -+ do { -+ debug("Wait SSH2_MSG_GSSAPI_INIT"); -+ type = packet_read(); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (dh_client_pub != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ recv_tok.value = packet_get_string(&slen); -+ recv_tok.length = slen; -+ -+ if ((dh_client_pub = BN_new()) == NULL) -+ fatal("dh_client_pub == NULL"); -+ -+ packet_get_bignum2(dh_client_pub); -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ recv_tok.value = packet_get_string(&slen); -+ recv_tok.length = slen; -+ break; -+ default: -+ packet_disconnect( -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ xfree(recv_tok.value); -+ -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (dh_client_pub == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, send_tok.length); -+ packet_send(); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, send_tok.length); -+ packet_send(); -+ } -+ fatal("accept_ctx died"); -+ } -+ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual Authentication flag wasn't set"); -+ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity flag wasn't set"); -+ -+ if (!dh_pub_is_valid(dh, dh_client_pub)) -+ packet_disconnect("bad client public DH value"); -+ -+ klen = DH_size(dh); -+ kbuf = xmalloc(klen); -+ kout = DH_compute_key(kbuf, dh_client_pub, dh); -+ if (kout < 0) -+ fatal("DH_compute_key: failed"); -+ -+ shared_secret = BN_new(); -+ if (shared_secret == NULL) -+ fatal("kexgss_server: BN_new failed"); -+ -+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) -+ fatal("kexgss_server: BN_bin2bn failed"); -+ -+ memset(kbuf, 0, klen); -+ xfree(kbuf); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( -+ kex->client_version_string, kex->server_version_string, -+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), -+ buffer_ptr(&kex->my), buffer_len(&kex->my), -+ NULL, 0, /* Change this if we start sending host keys */ -+ dh_client_pub, dh->pub_key, shared_secret, -+ &hash, &hashlen -+ ); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ kexgex_hash( -+ kex->evp_md, -+ kex->client_version_string, kex->server_version_string, -+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), -+ buffer_ptr(&kex->my), buffer_len(&kex->my), -+ NULL, 0, -+ min, nbits, max, -+ dh->p, dh->g, -+ dh_client_pub, -+ dh->pub_key, -+ shared_secret, -+ &hash, &hashlen -+ ); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ -+ BN_clear_free(dh_client_pub); -+ -+ if (kex->session_id == NULL) { -+ kex->session_id_len = hashlen; -+ kex->session_id = xmalloc(kex->session_id_len); -+ memcpy(kex->session_id, hash, kex->session_id_len); -+ } -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ packet_start(SSH2_MSG_KEXGSS_COMPLETE); -+ packet_put_bignum2(dh->pub_key); -+ packet_put_string(msg_tok.value,msg_tok.length); -+ -+ if (send_tok.length != 0) { -+ packet_put_char(1); /* true */ -+ packet_put_string(send_tok.value, send_tok.length); -+ } else { -+ packet_put_char(0); /* false */ -+ } -+ packet_send(); -+ -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ DH_free(dh); -+ -+ kex_derive_keys(kex, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ kex_finish(kex); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+} -+#endif /* GSSAPI */ -diff -up openssh-5.5p1/kex.h.gsskex openssh-5.5p1/kex.h ---- openssh-5.5p1/kex.h.gsskex 2010-02-26 21:55:05.000000000 +0100 -+++ openssh-5.5p1/kex.h 2010-05-13 15:59:59.000000000 +0200 -@@ -67,6 +67,9 @@ enum kex_exchange { - KEX_DH_GRP14_SHA1, - KEX_DH_GEX_SHA1, - KEX_DH_GEX_SHA256, -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GEX_SHA1, - KEX_MAX - }; - -@@ -123,6 +126,12 @@ struct Kex { - sig_atomic_t done; - int flags; - const EVP_MD *evp_md; -+#ifdef GSSAPI -+ int gss_deleg_creds; -+ int gss_trust_dns; -+ char *gss_host; -+ char *gss_client; -+#endif - char *client_version_string; - char *server_version_string; - int (*verify_host_key)(Key *); -@@ -146,6 +155,11 @@ void kexdh_server(Kex *); - void kexgex_client(Kex *); - void kexgex_server(Kex *); - -+#ifdef GSSAPI -+void kexgss_client(Kex *); -+void kexgss_server(Kex *); -+#endif -+ - void - kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, - BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); -diff -up openssh-5.5p1/key.c.gsskex openssh-5.5p1/key.c ---- openssh-5.5p1/key.c.gsskex 2010-03-21 19:58:24.000000000 +0100 -+++ openssh-5.5p1/key.c 2010-05-13 15:59:59.000000000 +0200 -@@ -982,6 +982,8 @@ key_type_from_name(char *name) - return KEY_RSA_CERT; - } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { - return KEY_DSA_CERT; -+ } else if (strcmp(name, "null") == 0) { -+ return KEY_NULL; - } - debug2("key_type_from_name: unknown key type '%s'", name); - return KEY_UNSPEC; -diff -up openssh-5.5p1/key.h.gsskex openssh-5.5p1/key.h ---- openssh-5.5p1/key.h.gsskex 2010-03-21 19:58:24.000000000 +0100 -+++ openssh-5.5p1/key.h 2010-05-13 15:59:59.000000000 +0200 -@@ -37,6 +37,7 @@ enum types { - KEY_DSA, - KEY_RSA_CERT, - KEY_DSA_CERT, -+ KEY_NULL, - KEY_UNSPEC - }; - enum fp_type { -diff -up openssh-5.5p1/Makefile.in.gsskex openssh-5.5p1/Makefile.in ---- openssh-5.5p1/Makefile.in.gsskex 2010-05-13 15:59:57.000000000 +0200 -+++ openssh-5.5p1/Makefile.in 2010-05-13 16:01:34.000000000 +0200 -@@ -76,11 +76,11 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b - monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ - kexgex.o kexdhc.o kexgexc.o msg.o progressmeter.o dns.o \ - entropy.o gss-genr.o umac.o jpake.o schnorr.o \ -- ssh-pkcs11.o -+ ssh-pkcs11.o kexgssc.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o \ -- roaming_common.o roaming_client.o -+ roaming_common.o roaming_client.o kexgssc.o - - SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ - sshpty.o sshlogin.o servconf.o serverloop.o \ -@@ -93,7 +93,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw - auth2-gss.o gss-serv.o gss-serv-krb5.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ -- roaming_common.o roaming_serv.o -+ roaming_common.o roaming_serv.o kexgsss.o - - MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out - MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5 -diff -up openssh-5.5p1/monitor.c.gsskex openssh-5.5p1/monitor.c ---- openssh-5.5p1/monitor.c.gsskex 2010-05-13 15:59:50.000000000 +0200 -+++ openssh-5.5p1/monitor.c 2010-05-13 15:59:59.000000000 +0200 -@@ -175,6 +175,8 @@ int mm_answer_gss_setup_ctx(int, Buffer - int mm_answer_gss_accept_ctx(int, Buffer *); - int mm_answer_gss_userok(int, Buffer *); - int mm_answer_gss_checkmic(int, Buffer *); -+int mm_answer_gss_sign(int, Buffer *); -+int mm_answer_gss_updatecreds(int, Buffer *); - #endif - - #ifdef SSH_AUDIT_EVENTS -@@ -247,6 +249,7 @@ struct mon_table mon_dispatch_proto20[] - {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, - {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, - {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, -+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, - #endif - #ifdef JPAKE - {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, -@@ -259,6 +262,12 @@ struct mon_table mon_dispatch_proto20[] - }; - - struct mon_table mon_dispatch_postauth20[] = { -+#ifdef GSSAPI -+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, -+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, -+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, -+ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, -+#endif - {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, - {MONITOR_REQ_SIGN, 0, mm_answer_sign}, - {MONITOR_REQ_PTY, 0, mm_answer_pty}, -@@ -363,6 +372,10 @@ monitor_child_preauth(Authctxt *_authctx - /* Permit requests for moduli and signatures */ - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - } else { - mon_dispatch = mon_dispatch_proto15; - -@@ -449,6 +462,10 @@ monitor_child_postauth(struct monitor *p - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - } else { - mon_dispatch = mon_dispatch_postauth15; - monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -@@ -1723,6 +1740,13 @@ mm_get_kex(Buffer *m) - kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; - kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; -+ } -+#endif - kex->server = 1; - kex->hostkey_type = buffer_get_int(m); - kex->kex_type = buffer_get_int(m); -@@ -1929,6 +1953,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer - OM_uint32 major; - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - goid.elements = buffer_get_string(m, &len); - goid.length = len; - -@@ -1956,6 +1983,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe - OM_uint32 flags = 0; /* GSI needs this */ - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - in.value = buffer_get_string(m, &len); - in.length = len; - major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); -@@ -1973,6 +2003,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); - } - return (0); - } -@@ -1984,6 +2015,9 @@ mm_answer_gss_checkmic(int sock, Buffer - OM_uint32 ret; - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - gssbuf.value = buffer_get_string(m, &len); - gssbuf.length = len; - mic.value = buffer_get_string(m, &len); -@@ -2010,7 +2044,11 @@ mm_answer_gss_userok(int sock, Buffer *m - { - int authenticated; - -- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ -+ authenticated = authctxt->valid && -+ ssh_gssapi_userok(authctxt->user, authctxt->pw); - - buffer_clear(m); - buffer_put_int(m, authenticated); -@@ -2023,6 +2061,74 @@ mm_answer_gss_userok(int sock, Buffer *m - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } -+ -+int -+mm_answer_gss_sign(int socket, Buffer *m) -+{ -+ gss_buffer_desc data; -+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; -+ OM_uint32 major, minor; -+ u_int len; -+ -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ -+ data.value = buffer_get_string(m, &len); -+ data.length = len; -+ if (data.length != 20) -+ fatal("%s: data length incorrect: %d", __func__, -+ (int) data.length); -+ -+ /* Save the session ID on the first time around */ -+ if (session_id2_len == 0) { -+ session_id2_len = data.length; -+ session_id2 = xmalloc(session_id2_len); -+ memcpy(session_id2, data.value, session_id2_len); -+ } -+ major = ssh_gssapi_sign(gsscontext, &data, &hash); -+ -+ xfree(data.value); -+ -+ buffer_clear(m); -+ buffer_put_int(m, major); -+ buffer_put_string(m, hash.value, hash.length); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); -+ -+ gss_release_buffer(&minor, &hash); -+ -+ /* Turn on getpwnam permissions */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); -+ -+ /* And credential updating, for when rekeying */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); -+ -+ return (0); -+} -+ -+int -+mm_answer_gss_updatecreds(int socket, Buffer *m) { -+ ssh_gssapi_ccache store; -+ int ok; -+ -+ store.filename = buffer_get_string(m, NULL); -+ store.envvar = buffer_get_string(m, NULL); -+ store.envval = buffer_get_string(m, NULL); -+ -+ ok = ssh_gssapi_update_creds(&store); -+ -+ xfree(store.filename); -+ xfree(store.envvar); -+ xfree(store.envval); -+ -+ buffer_clear(m); -+ buffer_put_int(m, ok); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); -+ -+ return(0); -+} -+ - #endif /* GSSAPI */ - - #ifdef JPAKE -diff -up openssh-5.5p1/monitor.h.gsskex openssh-5.5p1/monitor.h ---- openssh-5.5p1/monitor.h.gsskex 2010-05-13 15:59:50.000000000 +0200 -+++ openssh-5.5p1/monitor.h 2010-05-13 15:59:59.000000000 +0200 -@@ -56,6 +56,8 @@ enum monitor_reqtype { - MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, - MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, - MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, -+ MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, -+ MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, - MONITOR_REQ_PAM_START, - MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, - MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, -diff -up openssh-5.5p1/monitor_wrap.c.gsskex openssh-5.5p1/monitor_wrap.c ---- openssh-5.5p1/monitor_wrap.c.gsskex 2010-05-13 15:59:51.000000000 +0200 -+++ openssh-5.5p1/monitor_wrap.c 2010-05-13 15:59:59.000000000 +0200 -@@ -1250,7 +1250,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss - } - - int --mm_ssh_gssapi_userok(char *user) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw) - { - Buffer m; - int authenticated = 0; -@@ -1267,6 +1267,51 @@ mm_ssh_gssapi_userok(char *user) - debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); - return (authenticated); - } -+ -+OM_uint32 -+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) -+{ -+ Buffer m; -+ OM_uint32 major; -+ u_int len; -+ -+ buffer_init(&m); -+ buffer_put_string(&m, data->value, data->length); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); -+ -+ major = buffer_get_int(&m); -+ hash->value = buffer_get_string(&m, &len); -+ hash->length = len; -+ -+ buffer_free(&m); -+ -+ return(major); -+} -+ -+int -+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) -+{ -+ Buffer m; -+ int ok; -+ -+ buffer_init(&m); -+ -+ buffer_put_cstring(&m, store->filename ? store->filename : ""); -+ buffer_put_cstring(&m, store->envvar ? store->envvar : ""); -+ buffer_put_cstring(&m, store->envval ? store->envval : ""); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); -+ -+ ok = buffer_get_int(&m); -+ -+ buffer_free(&m); -+ -+ return (ok); -+} -+ - #endif /* GSSAPI */ - - #ifdef JPAKE -diff -up openssh-5.5p1/monitor_wrap.h.gsskex openssh-5.5p1/monitor_wrap.h ---- openssh-5.5p1/monitor_wrap.h.gsskex 2010-05-13 15:59:51.000000000 +0200 -+++ openssh-5.5p1/monitor_wrap.h 2010-05-13 15:59:59.000000000 +0200 -@@ -60,8 +60,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K - OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); - OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, - gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); --int mm_ssh_gssapi_userok(char *user); -+int mm_ssh_gssapi_userok(char *user, struct passwd *); - OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); -+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); -+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); - #endif - - #ifdef USE_PAM -diff -up openssh-5.5p1/readconf.c.gsskex openssh-5.5p1/readconf.c ---- openssh-5.5p1/readconf.c.gsskex 2010-02-11 23:21:03.000000000 +0100 -+++ openssh-5.5p1/readconf.c 2010-05-13 15:59:59.000000000 +0200 -@@ -127,6 +127,7 @@ typedef enum { - oClearAllForwardings, oNoHostAuthenticationForLocalhost, - oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, - oAddressFamily, oGssAuthentication, oGssDelegateCreds, -+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, - oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, - oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, -@@ -164,10 +165,18 @@ static struct { - { "afstokenpassing", oUnsupported }, - #if defined(GSSAPI) - { "gssapiauthentication", oGssAuthentication }, -+ { "gssapikeyexchange", oGssKeyEx }, - { "gssapidelegatecredentials", oGssDelegateCreds }, -+ { "gssapitrustdns", oGssTrustDns }, -+ { "gssapiclientidentity", oGssClientIdentity }, -+ { "gssapirenewalforcesrekey", oGssRenewalRekey }, - #else - { "gssapiauthentication", oUnsupported }, -+ { "gssapikeyexchange", oUnsupported }, - { "gssapidelegatecredentials", oUnsupported }, -+ { "gssapitrustdns", oUnsupported }, -+ { "gssapiclientidentity", oUnsupported }, -+ { "gssapirenewalforcesrekey", oUnsupported }, - #endif - { "fallbacktorsh", oDeprecated }, - { "usersh", oDeprecated }, -@@ -456,10 +465,26 @@ parse_flag: - intptr = &options->gss_authentication; - goto parse_flag; - -+ case oGssKeyEx: -+ intptr = &options->gss_keyex; -+ goto parse_flag; -+ - case oGssDelegateCreds: - intptr = &options->gss_deleg_creds; - goto parse_flag; - -+ case oGssTrustDns: -+ intptr = &options->gss_trust_dns; -+ goto parse_flag; -+ -+ case oGssClientIdentity: -+ charptr = &options->gss_client_identity; -+ goto parse_string; -+ -+ case oGssRenewalRekey: -+ intptr = &options->gss_renewal_rekey; -+ goto parse_flag; -+ - case oBatchMode: - intptr = &options->batch_mode; - goto parse_flag; -@@ -1015,7 +1040,11 @@ initialize_options(Options * options) - options->pubkey_authentication = -1; - options->challenge_response_authentication = -1; - options->gss_authentication = -1; -+ options->gss_keyex = -1; - options->gss_deleg_creds = -1; -+ options->gss_trust_dns = -1; -+ options->gss_renewal_rekey = -1; -+ options->gss_client_identity = NULL; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->kbd_interactive_devices = NULL; -@@ -1107,8 +1136,14 @@ fill_default_options(Options * options) - options->challenge_response_authentication = 1; - if (options->gss_authentication == -1) - options->gss_authentication = 0; -+ if (options->gss_keyex == -1) -+ options->gss_keyex = 0; - if (options->gss_deleg_creds == -1) - options->gss_deleg_creds = 0; -+ if (options->gss_trust_dns == -1) -+ options->gss_trust_dns = 0; -+ if (options->gss_renewal_rekey == -1) -+ options->gss_renewal_rekey = 0; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -diff -up openssh-5.5p1/readconf.h.gsskex openssh-5.5p1/readconf.h ---- openssh-5.5p1/readconf.h.gsskex 2010-02-11 23:21:03.000000000 +0100 -+++ openssh-5.5p1/readconf.h 2010-05-13 16:00:00.000000000 +0200 -@@ -44,7 +44,11 @@ typedef struct { - int challenge_response_authentication; - /* Try S/Key or TIS, authentication. */ - int gss_authentication; /* Try GSS authentication */ -+ int gss_keyex; /* Try GSS key exchange */ - int gss_deleg_creds; /* Delegate GSS credentials */ -+ int gss_trust_dns; /* Trust DNS for GSS canonicalization */ -+ int gss_renewal_rekey; /* Credential renewal forces rekey */ -+ char *gss_client_identity; /* Principal to initiate GSSAPI with */ - int password_authentication; /* Try password - * authentication. */ - int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff -up openssh-5.5p1/servconf.c.gsskex openssh-5.5p1/servconf.c ---- openssh-5.5p1/servconf.c.gsskex 2010-05-13 15:59:54.000000000 +0200 -+++ openssh-5.5p1/servconf.c 2010-05-13 16:00:00.000000000 +0200 -@@ -93,7 +93,10 @@ initialize_server_options(ServerOptions - options->kerberos_ticket_cleanup = -1; - options->kerberos_get_afs_token = -1; - options->gss_authentication=-1; -+ options->gss_keyex = -1; - options->gss_cleanup_creds = -1; -+ options->gss_strict_acceptor = -1; -+ options->gss_store_rekey = -1; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; -@@ -217,8 +220,14 @@ fill_default_server_options(ServerOption - options->kerberos_get_afs_token = 0; - if (options->gss_authentication == -1) - options->gss_authentication = 0; -+ if (options->gss_keyex == -1) -+ options->gss_keyex = 0; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; -+ if (options->gss_strict_acceptor == -1) -+ options->gss_strict_acceptor = 1; -+ if (options->gss_store_rekey == -1) -+ options->gss_store_rekey = 0; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -@@ -312,7 +321,9 @@ typedef enum { - sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, -- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, -+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -+ sGssKeyEx, sGssStoreRekey, -+ sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, - sZeroKnowledgePasswordAuthentication, sHostCertificate, -@@ -376,9 +387,15 @@ static struct { - #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, - #endif - { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, - { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, -@@ -939,10 +956,22 @@ process_server_config_line(ServerOptions - intptr = &options->gss_authentication; - goto parse_flag; - -+ case sGssKeyEx: -+ intptr = &options->gss_keyex; -+ goto parse_flag; -+ - case sGssCleanupCreds: - intptr = &options->gss_cleanup_creds; - goto parse_flag; - -+ case sGssStrictAcceptor: -+ intptr = &options->gss_strict_acceptor; -+ goto parse_flag; -+ -+ case sGssStoreRekey: -+ intptr = &options->gss_store_rekey; -+ goto parse_flag; -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -diff -up openssh-5.5p1/servconf.h.gsskex openssh-5.5p1/servconf.h ---- openssh-5.5p1/servconf.h.gsskex 2010-05-13 15:59:54.000000000 +0200 -+++ openssh-5.5p1/servconf.h 2010-05-13 16:00:00.000000000 +0200 -@@ -94,7 +94,10 @@ typedef struct { - int kerberos_get_afs_token; /* If true, try to get AFS token if - * authenticated with Kerberos. */ - int gss_authentication; /* If true, permit GSSAPI authentication */ -+ int gss_keyex; /* If true, permit GSSAPI key exchange */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -+ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ -+ int gss_store_rekey; - int password_authentication; /* If true, permit password - * authentication. */ - int kbd_interactive_authentication; /* If true, permit */ -diff -up openssh-5.5p1/ssh_config.5.gsskex openssh-5.5p1/ssh_config.5 ---- openssh-5.5p1/ssh_config.5.gsskex 2010-03-26 02:09:13.000000000 +0100 -+++ openssh-5.5p1/ssh_config.5 2010-05-13 16:00:00.000000000 +0200 -@@ -478,11 +478,38 @@ Specifies whether user authentication ba - The default is - .Dq no . - Note that this option applies to protocol version 2 only. -+.It Cm GSSAPIKeyExchange -+Specifies whether key exchange based on GSSAPI may be used. When using -+GSSAPI key exchange the server need not have a host key. -+The default is -+.Dq no . -+Note that this option applies to protocol version 2 only. -+.It Cm GSSAPIClientIdentity -+If set, specifies the GSSAPI client identity that ssh should use when -+connecting to the server. The default is unset, which means that the default -+identity will be used. - .It Cm GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. - The default is - .Dq no . --Note that this option applies to protocol version 2 only. -+Note that this option applies to protocol version 2 connections using GSSAPI. -+.It Cm GSSAPIRenewalForcesRekey -+If set to -+.Dq yes -+then renewal of the client's GSSAPI credentials will force the rekeying of the -+ssh connection. With a compatible server, this can delegate the renewed -+credentials to a session on the server. -+The default is -+.Dq no . -+.It Cm GSSAPITrustDns -+Set to -+.Dq yes to indicate that the DNS is trusted to securely canonicalize -+the name of the host being connected to. If -+.Dq no, the hostname entered on the -+command line will be passed untouched to the GSSAPI library. -+The default is -+.Dq no . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HashKnownHosts - Indicates that - .Xr ssh 1 -diff -up openssh-5.5p1/ssh_config.gsskex openssh-5.5p1/ssh_config ---- openssh-5.5p1/ssh_config.gsskex 2010-05-13 15:59:48.000000000 +0200 -+++ openssh-5.5p1/ssh_config 2010-05-13 16:00:00.000000000 +0200 -@@ -26,6 +26,8 @@ - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -diff -up openssh-5.5p1/sshconnect2.c.gsskex openssh-5.5p1/sshconnect2.c ---- openssh-5.5p1/sshconnect2.c.gsskex 2010-05-13 15:59:57.000000000 +0200 -+++ openssh-5.5p1/sshconnect2.c 2010-05-13 16:00:00.000000000 +0200 -@@ -108,9 +108,34 @@ ssh_kex2(char *host, struct sockaddr *ho - { - Kex *kex; - -+#ifdef GSSAPI -+ char *orig = NULL, *gss = NULL; -+ char *gss_host = NULL; -+#endif -+ - xxx_host = host; - xxx_hostaddr = hostaddr; - -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ if (options.gss_trust_dns) -+ gss_host = (char *)get_canonical_hostname(1); -+ else -+ gss_host = host; -+ -+ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ } -+ } -+#endif -+ - if (options.ciphers == (char *)-1) { - logit("No valid ciphers for protocol version 2 given, using defaults."); - options.ciphers = NULL; -@@ -146,6 +171,17 @@ ssh_kex2(char *host, struct sockaddr *ho - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = - options.hostkeyalgorithms; - -+#ifdef GSSAPI -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ if (options.gss_keyex && gss) { -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ xfree(gss); -+ } -+#endif -+ - if (options.rekey_limit) - packet_set_rekey_limit((u_int32_t)options.rekey_limit); - -@@ -155,10 +191,26 @@ ssh_kex2(char *host, struct sockaddr *ho - kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; - kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; - kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; -+ } -+#endif - kex->client_version_string=client_version_string; - kex->server_version_string=server_version_string; - kex->verify_host_key=&verify_host_key_callback; - -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->gss_deleg_creds = options.gss_deleg_creds; -+ kex->gss_trust_dns = options.gss_trust_dns; -+ kex->gss_client = options.gss_client_identity; -+ kex->gss_host = gss_host; -+ } -+#endif -+ - xxx_kex = kex; - - dispatch_run(DISPATCH_BLOCK, &kex->done, kex); -@@ -253,6 +305,7 @@ void input_gssapi_token(int type, u_int3 - void input_gssapi_hash(int type, u_int32_t, void *); - void input_gssapi_error(int, u_int32_t, void *); - void input_gssapi_errtok(int, u_int32_t, void *); -+int userauth_gsskeyex(Authctxt *authctxt); - #endif - - void userauth(Authctxt *, char *); -@@ -268,6 +321,10 @@ static char *authmethods_get(void); - - Authmethod authmethods[] = { - #ifdef GSSAPI -+ {"gssapi-keyex", -+ userauth_gsskeyex, -+ &options.gss_authentication, -+ NULL}, - {"gssapi-with-mic", - userauth_gssapi, - NULL, -@@ -576,23 +633,35 @@ userauth_gssapi(Authctxt *authctxt) - int ok = 0; - char* remotehost = NULL; - const char* canonicalhost = get_canonical_hostname(1); -+ const char *gss_host; -+ - if ( strcmp( canonicalhost, "UNKNOWN" ) == 0 ) - remotehost = authctxt->host; - else - remotehost = canonicalhost; - -+ if (options.gss_trust_dns) -+// gss_host = get_canonical_hostname(1); -+ gss_host = remotehost; -+ else -+ gss_host = authctxt->host; -+ - /* Try one GSSAPI method at a time, rather than sending them all at - * once. */ - - if (gss_supported == NULL) -- gss_indicate_mechs(&min, &gss_supported); -+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { -+ gss_supported = NULL; -+ return 0; -+ } - - /* Check to see if the mechanism is usable before we offer it */ - while (mech < gss_supported->count && !ok) { - /* My DER encoding requires length<128 */ - if (gss_supported->elements[mech].length < 128 && - ssh_gssapi_check_mechanism(&gssctxt, -- &gss_supported->elements[mech], remotehost)) { -+ &gss_supported->elements[mech], gss_host, -+ options.gss_client_identity)) { - ok = 1; /* Mechanism works */ - } else { - mech++; -@@ -689,8 +758,8 @@ input_gssapi_response(int type, u_int32_ - { - Authctxt *authctxt = ctxt; - Gssctxt *gssctxt; -- int oidlen; -- char *oidv; -+ u_int oidlen; -+ u_char *oidv; - - if (authctxt == NULL) - fatal("input_gssapi_response: no authentication context"); -@@ -800,6 +869,48 @@ input_gssapi_error(int type, u_int32_t p - xfree(msg); - xfree(lang); - } -+ -+int -+userauth_gsskeyex(Authctxt *authctxt) -+{ -+ Buffer b; -+ gss_buffer_desc gssbuf; -+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; -+ OM_uint32 ms; -+ -+ static int attempt = 0; -+ if (attempt++ >= 1) -+ return (0); -+ -+ if (gss_kex_context == NULL) { -+ debug("No valid Key exchange context"); -+ return (0); -+ } -+ -+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, -+ "gssapi-keyex"); -+ -+ gssbuf.value = buffer_ptr(&b); -+ gssbuf.length = buffer_len(&b); -+ -+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { -+ buffer_free(&b); -+ return (0); -+ } -+ -+ packet_start(SSH2_MSG_USERAUTH_REQUEST); -+ packet_put_cstring(authctxt->server_user); -+ packet_put_cstring(authctxt->service); -+ packet_put_cstring(authctxt->method->name); -+ packet_put_string(mic.value, mic.length); -+ packet_send(); -+ -+ buffer_free(&b); -+ gss_release_buffer(&ms, &mic); -+ -+ return (1); -+} -+ - #endif /* GSSAPI */ - - int -diff -up openssh-5.5p1/sshd.c.gsskex openssh-5.5p1/sshd.c ---- openssh-5.5p1/sshd.c.gsskex 2010-05-13 15:59:57.000000000 +0200 -+++ openssh-5.5p1/sshd.c 2010-05-13 16:00:00.000000000 +0200 -@@ -129,6 +129,10 @@ int allow_severity; - int deny_severity; - #endif /* LIBWRAP */ - -+#ifdef USE_SECURITY_SESSION_API -+#include -+#endif -+ - #ifndef O_NOCTTY - #define O_NOCTTY 0 - #endif -@@ -1592,10 +1596,13 @@ main(int ac, char **av) - logit("Disabling protocol version 1. Could not load host key"); - options.protocol &= ~SSH_PROTO_1; - } -+#ifndef GSSAPI -+ /* The GSSAPI key exchange can run without a host key */ - if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { - logit("Disabling protocol version 2. Could not load host key"); - options.protocol &= ~SSH_PROTO_2; - } -+#endif - if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { - logit("sshd: no hostkeys available -- exiting."); - exit(1); -@@ -1928,6 +1935,60 @@ main(int ac, char **av) - /* Log the connection. */ - verbose("Connection from %.500s port %d", remote_ip, remote_port); - -+#ifdef USE_SECURITY_SESSION_API -+ /* -+ * Create a new security session for use by the new user login if -+ * the current session is the root session or we are not launched -+ * by inetd (eg: debugging mode or server mode). We do not -+ * necessarily need to create a session if we are launched from -+ * inetd because Panther xinetd will create a session for us. -+ * -+ * The only case where this logic will fail is if there is an -+ * inetd running in a non-root session which is not creating -+ * new sessions for us. Then all the users will end up in the -+ * same session (bad). -+ * -+ * When the client exits, the session will be destroyed for us -+ * automatically. -+ * -+ * We must create the session before any credentials are stored -+ * (including AFS pags, which happens a few lines below). -+ */ -+ { -+ OSStatus err = 0; -+ SecuritySessionId sid = 0; -+ SessionAttributeBits sattrs = 0; -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("Current Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ -+ if (inetd_flag && !(sattrs & sessionIsRoot)) -+ debug("Running in inetd mode in a non-root session... " -+ "assuming inetd created the session for us."); -+ else { -+ debug("Creating new security session..."); -+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); -+ if (err) -+ error("SessionCreate() failed with error %.8X", -+ (unsigned) err); -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, -+ &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("New Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ } -+ } -+#endif -+ - /* - * We don't want to listen forever unless the other side - * successfully authenticates itself. So we set up an alarm which is -@@ -2315,12 +2376,61 @@ do_ssh2_kex(void) - - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); - -+#ifdef GSSAPI -+ { -+ char *orig; -+ char *gss = NULL; -+ char *newstr = NULL; -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ /* -+ * If we don't have a host key, then there's no point advertising -+ * the other key exchange algorithms -+ */ -+ -+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) -+ orig = NULL; -+ -+ if (options.gss_keyex) -+ gss = ssh_gssapi_server_mechanisms(); -+ else -+ gss = NULL; -+ -+ if (gss && orig) -+ xasprintf(&newstr, "%s,%s", gss, orig); -+ else if (gss) -+ newstr = gss; -+ else if (orig) -+ newstr = orig; -+ -+ /* -+ * If we've got GSSAPI mechanisms, then we've got the 'null' host -+ * key alg, but we can't tell people about it unless its the only -+ * host key algorithm we support -+ */ -+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; -+ -+ if (newstr) -+ myproposal[PROPOSAL_KEX_ALGS] = newstr; -+ else -+ fatal("No supported key exchange algorithms"); -+ } -+#endif -+ - /* start key exchange */ - kex = kex_setup(myproposal); - kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; - kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; - kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; -+ } -+#endif - kex->server = 1; - kex->client_version_string=client_version_string; - kex->server_version_string=server_version_string; -diff -up openssh-5.5p1/sshd_config.5.gsskex openssh-5.5p1/sshd_config.5 ---- openssh-5.5p1/sshd_config.5.gsskex 2010-05-13 15:59:54.000000000 +0200 -+++ openssh-5.5p1/sshd_config.5 2010-05-13 16:00:00.000000000 +0200 -@@ -379,12 +379,40 @@ Specifies whether user authentication ba - The default is - .Dq no . - Note that this option applies to protocol version 2 only. -+.It Cm GSSAPIKeyExchange -+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange -+doesn't rely on ssh keys to verify host identity. -+The default is -+.Dq no . -+Note that this option applies to protocol version 2 only. - .It Cm GSSAPICleanupCredentials - Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Dq yes . - Note that this option applies to protocol version 2 only. -+.It Cm GSSAPIStrictAcceptorCheck -+Determines whether to be strict about the identity of the GSSAPI acceptor -+a client authenticates against. If -+.Dq yes -+then the client must authenticate against the -+.Pa host -+service on the current hostname. If -+.Dq no -+then the client may authenticate against any service key stored in the -+machine's default store. This facility is provided to assist with operation -+on multi homed machines. -+The default is -+.Dq yes . -+Note that this option applies only to protocol version 2 GSSAPI connections, -+and setting it to -+.Dq no -+may only work with recent Kerberos GSSAPI libraries. -+.It Cm GSSAPIStoreCredentialsOnRekey -+Controls whether the user's GSSAPI credentials should be updated following a -+successful connection rekeying. This option can be used to accepted renewed -+or updated credentials from a compatible client. The default is -+.Dq no . - .It Cm HostbasedAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication together - with successful public key client host authentication is allowed -diff -up openssh-5.5p1/sshd_config.gsskex openssh-5.5p1/sshd_config ---- openssh-5.5p1/sshd_config.gsskex 2010-05-13 15:59:54.000000000 +0200 -+++ openssh-5.5p1/sshd_config 2010-05-13 16:00:00.000000000 +0200 -@@ -78,6 +78,8 @@ ChallengeResponseAuthentication no - GSSAPIAuthentication yes - #GSSAPICleanupCredentials yes - GSSAPICleanupCredentials yes -+#GSSAPIStrictAcceptorCheck yes -+#GSSAPIKeyExchange no - - # Set this to 'yes' to enable PAM authentication, account processing, - # and session processing. If this is enabled, PAM authentication will -diff -up openssh-5.5p1/ssh-gss.h.gsskex openssh-5.5p1/ssh-gss.h ---- openssh-5.5p1/ssh-gss.h.gsskex 2007-06-12 15:40:39.000000000 +0200 -+++ openssh-5.5p1/ssh-gss.h 2010-05-13 16:00:00.000000000 +0200 -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -60,10 +60,22 @@ - - #define SSH_GSS_OIDTYPE 0x06 - -+#define SSH2_MSG_KEXGSS_INIT 30 -+#define SSH2_MSG_KEXGSS_CONTINUE 31 -+#define SSH2_MSG_KEXGSS_COMPLETE 32 -+#define SSH2_MSG_KEXGSS_HOSTKEY 33 -+#define SSH2_MSG_KEXGSS_ERROR 34 -+#define SSH2_MSG_KEXGSS_GROUPREQ 40 -+#define SSH2_MSG_KEXGSS_GROUP 41 -+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" -+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" -+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" -+ - typedef struct { - char *filename; - char *envvar; - char *envval; -+ struct passwd *owner; - void *data; - } ssh_gssapi_ccache; - -@@ -71,8 +83,11 @@ typedef struct { - gss_buffer_desc displayname; - gss_buffer_desc exportedname; - gss_cred_id_t creds; -+ gss_name_t name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ int used; -+ int updated; - } ssh_gssapi_client; - - typedef struct ssh_gssapi_mech_struct { -@@ -83,6 +98,7 @@ typedef struct ssh_gssapi_mech_struct { - int (*userok) (ssh_gssapi_client *, char *); - int (*localname) (ssh_gssapi_client *, char **); - void (*storecreds) (ssh_gssapi_client *); -+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); - } ssh_gssapi_mech; - - typedef struct { -@@ -93,10 +109,11 @@ typedef struct { - gss_OID oid; /* client */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ -- gss_cred_id_t client_creds; /* server */ -+ gss_cred_id_t client_creds; /* both */ - } Gssctxt; - - extern ssh_gssapi_mech *supported_mechs[]; -+extern Gssctxt *gss_kex_context; - - int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); - void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); -@@ -116,16 +133,30 @@ void ssh_gssapi_build_ctx(Gssctxt **); - void ssh_gssapi_delete_ctx(Gssctxt **); - OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); --int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); -+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); -+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); -+int ssh_gssapi_credentials_updated(Gssctxt *); - - /* In the server */ -+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, -+ const char *); -+char *ssh_gssapi_client_mechanisms(const char *, const char *); -+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, -+ const char *); -+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); -+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, -+ const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); --int ssh_gssapi_userok(char *name); -+int ssh_gssapi_userok(char *name, struct passwd *); - OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_do_child(char ***, u_int *); - void ssh_gssapi_cleanup_creds(void); - void ssh_gssapi_storecreds(void); - -+char *ssh_gssapi_server_mechanisms(void); -+int ssh_gssapi_oid_table_ok(); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ diff --git a/openssh-5.5p1-keygen.patch b/openssh-5.5p1-keygen.patch deleted file mode 100644 index c7a8fb4..0000000 --- a/openssh-5.5p1-keygen.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff -up openssh-5.5p1/ssh-keygen.0.keygen openssh-5.5p1/ssh-keygen.0 ---- openssh-5.5p1/ssh-keygen.0.keygen 2010-04-16 02:17:11.000000000 +0200 -+++ openssh-5.5p1/ssh-keygen.0 2010-05-04 08:19:22.000000000 +0200 -@@ -4,7 +4,7 @@ NAME - ssh-keygen - authentication key generation, management and conversion - - SYNOPSIS -- ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment] -+ ssh-keygen [-q] [-o] [-b bits] -t type [-N new_passphrase] [-C comment] - [-f output_keyfile] - ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile] - ssh-keygen -i [-f input_keyfile] -@@ -222,6 +222,8 @@ DESCRIPTION - - -q Silence ssh-keygen. Used by /etc/rc when creating a new key. - -+ -o Overwrite the key without prompting user. -+ - -R hostname - Removes all keys belonging to hostname from a known_hosts file. - This option is useful to delete hashed hosts (see the -H option -diff -up openssh-5.5p1/ssh-keygen.1.keygen openssh-5.5p1/ssh-keygen.1 ---- openssh-5.5p1/ssh-keygen.1.keygen 2010-03-21 19:57:49.000000000 +0100 -+++ openssh-5.5p1/ssh-keygen.1 2010-05-04 08:19:22.000000000 +0200 -@@ -47,6 +47,7 @@ - .Nm ssh-keygen - .Bk -words - .Op Fl q -+.Op Fl o - .Op Fl b Ar bits - .Fl t Ar type - .Op Fl N Ar new_passphrase -@@ -370,6 +371,8 @@ Silence - Used by - .Pa /etc/rc - when creating a new key. -+.It Fl o -+Overwrite the key without prompting user. - .It Fl R Ar hostname - Removes all keys belonging to - .Ar hostname -diff -up openssh-5.5p1/ssh-keygen.c.keygen openssh-5.5p1/ssh-keygen.c ---- openssh-5.5p1/ssh-keygen.c.keygen 2010-03-21 19:58:24.000000000 +0100 -+++ openssh-5.5p1/ssh-keygen.c 2010-05-04 08:22:22.000000000 +0200 -@@ -72,6 +72,7 @@ int change_passphrase = 0; - int change_comment = 0; - - int quiet = 0; -+int overwrite = 0; - - int log_level = SYSLOG_LEVEL_INFO; - -@@ -1540,7 +1541,7 @@ main(int argc, char **argv) - exit(1); - } - -- while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" -+ while ((opt = getopt(argc, argv, "degiqopclBHLhvxXyF:b:f:t:D:I:P:N:n:" - "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { - switch (opt) { - case 'b': -@@ -1605,6 +1606,9 @@ main(int argc, char **argv) - case 'q': - quiet = 1; - break; -+ case 'o': -+ overwrite = 1; -+ break; - case 'e': - case 'x': - /* export key */ -@@ -1835,7 +1839,7 @@ main(int argc, char **argv) - printf("Created directory '%s'.\n", dotsshdir); - } - /* If the file already exists, ask the user to confirm. */ -- if (stat(identity_file, &st) >= 0) { -+ if (!overwrite && stat(identity_file, &st) >= 0) { - char yesno[3]; - printf("%s already exists.\n", identity_file); - printf("Overwrite (y/n)? "); diff --git a/openssh-5.5p1-kuserok.patch b/openssh-5.5p1-kuserok.patch deleted file mode 100644 index 2390745..0000000 --- a/openssh-5.5p1-kuserok.patch +++ /dev/null @@ -1,132 +0,0 @@ -diff -up openssh-5.5p1/auth-krb5.c.kuserok openssh-5.5p1/auth-krb5.c ---- openssh-5.5p1/auth-krb5.c.kuserok 2010-07-07 13:12:01.000000000 +0200 -+++ openssh-5.5p1/auth-krb5.c 2010-07-07 13:12:03.000000000 +0200 -@@ -146,9 +146,11 @@ auth_krb5_password(Authctxt *authctxt, c - if (problem) - goto out; - -- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { -- problem = -1; -- goto out; -+ if (options.use_kuserok) { -+ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { -+ problem = -1; -+ goto out; -+ } - } - - problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); -diff -up openssh-5.5p1/servconf.c.kuserok openssh-5.5p1/servconf.c ---- openssh-5.5p1/servconf.c.kuserok 2010-07-07 13:12:02.000000000 +0200 -+++ openssh-5.5p1/servconf.c 2010-07-07 13:12:04.000000000 +0200 -@@ -137,6 +137,7 @@ initialize_server_options(ServerOptions - options->zero_knowledge_password_authentication = -1; - options->revoked_keys_file = NULL; - options->trusted_user_ca_keys = NULL; -+ options->use_kuserok = -1; - } - - void -@@ -285,6 +286,8 @@ fill_default_server_options(ServerOption - if (use_privsep == -1) - use_privsep = 1; - -+ if (options->use_kuserok == -1) -+ options->use_kuserok = 1; - #ifndef HAVE_MMAP - if (use_privsep && options->compression == 1) { - error("This platform does not support both privilege " -@@ -306,7 +309,7 @@ typedef enum { - sPermitRootLogin, sLogFacility, sLogLevel, - sRhostsRSAAuthentication, sRSAAuthentication, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, -- sKerberosGetAFSToken, -+ sKerberosGetAFSToken, sKerberosUseKuserok, - sKerberosTgtPassing, sChallengeResponseAuthentication, - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, -@@ -376,11 +379,13 @@ static struct { - #else - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, - #endif -+ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL }, - #else - { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, - { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, -+ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL }, - #endif - { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, - { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1335,6 +1340,10 @@ process_server_config_line(ServerOptions - *activep = value; - break; - -+ case sKerberosUseKuserok: -+ intptr = &options->use_kuserok; -+ goto parse_flag; -+ - case sPermitOpen: - arg = strdelim(&cp); - if (!arg || *arg == '\0') -@@ -1517,6 +1526,7 @@ copy_set_server_options(ServerOptions *d - M_CP_INTOPT(x11_use_localhost); - M_CP_INTOPT(max_sessions); - M_CP_INTOPT(max_authtries); -+ M_CP_INTOPT(use_kuserok); - - M_CP_STROPT(banner); - if (preauth) -@@ -1734,6 +1744,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sUseDNS, o->use_dns); - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); -+ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); - - /* string arguments */ - dump_cfg_string(sPidFile, o->pid_file); -diff -up openssh-5.5p1/servconf.h.kuserok openssh-5.5p1/servconf.h ---- openssh-5.5p1/servconf.h.kuserok 2010-07-07 13:12:02.000000000 +0200 -+++ openssh-5.5p1/servconf.h 2010-07-07 13:12:04.000000000 +0200 -@@ -157,6 +157,7 @@ typedef struct { - - int num_permitted_opens; - -+ int use_kuserok; - char *chroot_directory; - char *revoked_keys_file; - char *trusted_user_ca_keys; -diff -up openssh-5.5p1/sshd_config.5.kuserok openssh-5.5p1/sshd_config.5 ---- openssh-5.5p1/sshd_config.5.kuserok 2010-07-07 13:12:03.000000000 +0200 -+++ openssh-5.5p1/sshd_config.5 2010-07-07 13:21:02.000000000 +0200 -@@ -519,6 +519,10 @@ Specifies whether to automatically destr - file on logout. - The default is - .Dq yes . -+.It Cm KerberosUseKuserok -+Specifies whether to look at .k5login file for user's aliases. -+The default is -+.Dq yes . - .It Cm KeyRegenerationInterval - In protocol version 1, the ephemeral server key is automatically regenerated - after this many seconds (if it has been used). -@@ -644,6 +648,7 @@ Available keywords are - .Cm HostbasedAuthentication , - .Cm KbdInteractiveAuthentication , - .Cm KerberosAuthentication , -+.Cm KerberosUseKuserok , - .Cm MaxAuthTries , - .Cm MaxSessions , - .Cm PubkeyAuthentication , -diff -up openssh-5.5p1/sshd_config.kuserok openssh-5.5p1/sshd_config ---- openssh-5.5p1/sshd_config.kuserok 2010-07-07 13:12:03.000000000 +0200 -+++ openssh-5.5p1/sshd_config 2010-07-07 13:12:04.000000000 +0200 -@@ -72,6 +72,7 @@ ChallengeResponseAuthentication no - #KerberosOrLocalPasswd yes - #KerberosTicketCleanup yes - #KerberosGetAFSToken no -+#KerberosUseKuserok yes - - # GSSAPI options - #GSSAPIAuthentication no diff --git a/openssh-5.5p1-ldap.patch b/openssh-5.5p1-ldap.patch deleted file mode 100644 index 172477f..0000000 --- a/openssh-5.5p1-ldap.patch +++ /dev/null @@ -1,2876 +0,0 @@ -diff -up openssh-5.5p1/configure.ac.ldap openssh-5.5p1/configure.ac ---- openssh-5.5p1/configure.ac.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/configure.ac 2010-07-07 14:36:34.000000000 +0200 -@@ -1358,6 +1358,106 @@ AC_ARG_WITH(authorized-keys-command, - ] - ) - -+# Check whether user wants LDAP support -+LDAP_MSG="no" -+INSTALL_SSH_LDAP_HELPER="" -+AC_ARG_WITH(ldap, -+ [ --with-ldap[[=PATH]] Enable LDAP pubkey support (optionally in PATH)], -+ [ -+ if test "x$withval" != "xno" ; then -+ -+ INSTALL_SSH_LDAP_HELPER="yes" -+ CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED" -+ -+ if test "x$withval" != "xyes" ; then -+ CPPFLAGS="$CPPFLAGS -I${withval}/include" -+ LDFLAGS="$LDFLAGS -L${withval}/lib" -+ fi -+ -+ AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support]) -+ LDAP_MSG="yes" -+ -+ AC_CHECK_HEADERS(lber.h) -+ AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate )) -+ AC_CHECK_HEADERS(ldap_ssl.h) -+ -+ AC_ARG_WITH(ldap-lib, -+ [ --with-ldap-lib=type select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]]) -+ -+ if test -z "$with_ldap_lib"; then -+ with_ldap_lib=auto -+ fi -+ -+ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then -+ AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes) -+ AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes) -+ fi -+ -+ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then -+ AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes) -+ fi -+ -+ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then -+ AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes) -+ if test -z "$found_ldap_lib"; then -+ AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes) -+ fi -+ if test -z "$found_ldap_lib"; then -+ AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes) -+ fi -+ if test -z "$found_ldap_lib"; then -+ AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes) -+ fi -+ fi -+ -+ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then -+ AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes) -+ fi -+ -+ if test -z "$found_ldap_lib"; then -+ AC_MSG_ERROR(could not locate a valid LDAP library) -+ fi -+ -+ AC_MSG_CHECKING([for working LDAP support]) -+ AC_TRY_COMPILE( -+ [#include -+ #include ], -+ [(void)ldap_init(0, 0);], -+ [AC_MSG_RESULT(yes)], -+ [ -+ AC_MSG_RESULT(no) -+ AC_MSG_ERROR([** Incomplete or missing ldap libraries **]) -+ ]) -+ AC_CHECK_FUNCS( \ -+ ldap_init \ -+ ldap_get_lderrno \ -+ ldap_set_lderrno \ -+ ldap_parse_result \ -+ ldap_memfree \ -+ ldap_controls_free \ -+ ldap_set_option \ -+ ldap_get_option \ -+ ldapssl_init \ -+ ldap_start_tls_s \ -+ ldap_pvt_tls_set_option \ -+ ldap_initialize \ -+ ) -+ AC_CHECK_FUNCS(ldap_set_rebind_proc, -+ AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc]) -+ AC_TRY_COMPILE( -+ [#include -+ #include ], -+ [ldap_set_rebind_proc(0, 0, 0);], -+ [ac_cv_ldap_set_rebind_proc=3], -+ [ac_cv_ldap_set_rebind_proc=2]) -+ AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc) -+ AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc]) -+ ) -+ fi -+ ] -+) -+AC_SUBST(INSTALL_SSH_LDAP_HELPER) -+ - dnl Checks for library functions. Please keep in alphabetical order - AC_CHECK_FUNCS( \ - arc4random \ -diff -up openssh-5.5p1/ldapbody.c.ldap openssh-5.5p1/ldapbody.c ---- openssh-5.5p1/ldapbody.c.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapbody.c 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,494 @@ -+/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "ldapincludes.h" -+#include "log.h" -+#include "xmalloc.h" -+#include "ldapconf.h" -+#include "ldapmisc.h" -+#include "ldapbody.h" -+#include -+#include -+ -+#define LDAPSEARCH_FORMAT "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)" -+#define PUBKEYATTR "sshPublicKey" -+#define LDAP_LOGFILE "%s/ldap.%d" -+ -+static FILE *logfile = NULL; -+static LDAP *ld; -+ -+static char *attrs[] = { -+ PUBKEYATTR, -+ NULL -+}; -+ -+void -+ldap_checkconfig (void) -+{ -+#ifdef HAVE_LDAP_INITIALIZE -+ if (options.host == NULL && options.uri == NULL) -+#else -+ if (options.host == NULL) -+#endif -+ fatal ("missing \"host\" in config file"); -+} -+ -+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) -+static int -+_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid) -+{ -+ struct timeval timeout; -+ int rc; -+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) -+ LDAPMessage *result; -+#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ -+ -+ debug2 ("Doing LDAP rebind to %s", options.binddn); -+ if (options.ssl == SSL_START_TLS) { -+ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) { -+ error ("ldap_starttls_s: %s", ldap_err2string (rc)); -+ return LDAP_OPERATIONS_ERROR; -+ } -+ } -+ -+#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE) -+ return ldap_simple_bind_s (ld, options.binddn, options.bindpw); -+#else -+ if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0) -+ fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); -+ -+ timeout.tv_sec = options.bind_timelimit; -+ timeout.tv_usec = 0; -+ result = NULL; -+ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { -+ error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); -+ ldap_msgfree (result); -+ return LDAP_OPERATIONS_ERROR; -+ } -+ debug3 ("LDAP rebind to %s succesfull", options.binddn); -+ return rc; -+#endif -+} -+#else -+ -+static int -+_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit) -+{ -+ if (freeit) -+ return LDAP_SUCCESS; -+ -+ *whop = strdup (options.binddn); -+ *credp = strdup (options.bindpw); -+ *methodp = LDAP_AUTH_SIMPLE; -+ debug2 ("Doing LDAP rebind for %s", *whop); -+ return LDAP_SUCCESS; -+} -+#endif -+ -+void -+ldap_do_connect(void) -+{ -+ int rc, msgid, ld_errno = 0; -+ struct timeval timeout; -+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) -+ int parserc; -+ LDAPMessage *result; -+ LDAPControl **controls; -+ int reconnect = 0; -+#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ -+ -+ debug ("LDAP do connect"); -+ -+retry: -+ if (reconnect) { -+ debug3 ("Reconnecting with ld_errno %d", ld_errno); -+ if (options.bind_policy == 0 || -+ (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) || -+ reconnect > 5) -+ fatal ("Cannot connect to LDAP server"); -+ -+ if (reconnect > 1) -+ sleep (reconnect - 1); -+ -+ if (ld != NULL) { -+ ldap_unbind (ld); -+ ld = NULL; -+ } -+ logit("reconnecting to LDAP server..."); -+ } -+ -+ if (ld == NULL) { -+ int rc; -+ struct timeval tv; -+ -+#ifdef HAVE_LDAP_SET_OPTION -+ if (options.debug > 0) { -+#ifdef LBER_OPT_LOG_PRINT_FILE -+ if (options.logdir) { -+ char *logfilename; -+ int logfilenamelen; -+ -+ logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir); -+ logfilename = xmalloc (logfilenamelen); -+ snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ()); -+ logfilename[logfilenamelen - 1] = 0; -+ if ((logfile = fopen (logfilename, "a")) == NULL) -+ fatal ("cannot append to %s: %s", logfilename, strerror (errno)); -+ debug3 ("LDAP debug into %s", logfilename); -+ xfree (logfilename); -+ ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile); -+ } -+#endif -+ if (options.debug) { -+#ifdef LBER_OPT_DEBUG_LEVEL -+ ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug); -+#endif /* LBER_OPT_DEBUG_LEVEL */ -+#ifdef LDAP_OPT_DEBUG_LEVEL -+ ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug); -+#endif /* LDAP_OPT_DEBUG_LEVEL */ -+ debug3 ("Set LDAP debug to %d", options.debug); -+ } -+ } -+#endif /* HAVE_LDAP_SET_OPTION */ -+ -+ ld = NULL; -+#ifdef HAVE_LDAPSSL_INIT -+ if (options.host != NULL) { -+ if (options.ssl_on == SSL_LDAPS) { -+ if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS) -+ fatal ("ldapssl_client_init %s", ldap_err2string (rc)); -+ debug3 ("LDAPssl client init"); -+ } -+ -+ if (options.ssl_on != SSL_OFF) { -+ if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL) -+ fatal ("ldapssl_init failed"); -+ debug3 ("LDAPssl init"); -+ } -+ } -+#endif /* HAVE_LDAPSSL_INIT */ -+ -+ /* continue with opening */ -+ if (ld == NULL) { -+#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) -+ /* Some global TLS-specific options need to be set before we create our -+ * session context, so we set them here. */ -+ -+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE -+ /* rand file */ -+ if (options.tls_randfile != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE, -+ options.tls_randfile)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS random file %s", options.tls_randfile); -+ } -+#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */ -+ -+ /* ca cert file */ -+ if (options.tls_cacertfile != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, -+ options.tls_cacertfile)) != LDAP_SUCCESS) -+ error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile); -+ } -+ -+ /* ca cert directory */ -+ if (options.tls_cacertdir != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, -+ options.tls_cacertdir)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir); -+ } -+ -+ /* require cert? */ -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, -+ &options.tls_checkpeer)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS check peer to %d ", options.tls_checkpeer); -+ -+ /* set cipher suite, certificate and private key: */ -+ if (options.tls_ciphers != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, -+ options.tls_ciphers)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS ciphers to %s ", options.tls_ciphers); -+ } -+ -+ /* cert file */ -+ if (options.tls_cert != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, -+ options.tls_cert)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS cert file %s ", options.tls_cert); -+ } -+ -+ /* key file */ -+ if (options.tls_key != NULL) { -+ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, -+ options.tls_key)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s", -+ ldap_err2string (rc)); -+ debug3 ("Set TLS key file %s ", options.tls_key); -+ } -+#endif -+#ifdef HAVE_LDAP_INITIALIZE -+ if (options.uri != NULL) { -+ if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS) -+ fatal ("ldap_initialize %s", ldap_err2string (rc)); -+ debug3 ("LDAP initialize %s", options.uri); -+ } -+ } -+#endif /* HAVE_LDAP_INTITIALIZE */ -+ -+ /* continue with opening */ -+ if ((ld == NULL) && (options.host != NULL)) { -+#ifdef HAVE_LDAP_INIT -+ if ((ld = ldap_init (options.host, options.port)) == NULL) -+ fatal ("ldap_init failed"); -+ debug3 ("LDAP init %s:%d", options.host, options.port); -+#else -+ if ((ld = ldap_open (options.host, options.port)) == NULL) -+ fatal ("ldap_open failed"); -+ debug3 ("LDAP open %s:%d", options.host, options.port); -+#endif /* HAVE_LDAP_INIT */ -+ } -+ -+ if (ld == NULL) -+ fatal ("no way to open ldap"); -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) -+ if (options.ssl == SSL_LDAPS) { -+ if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS) -+ fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc)); -+ debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer); -+ } -+#endif /* LDAP_OPT_X_TLS */ -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION) -+ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, -+ &options.ldap_version); -+#else -+ ld->ld_version = options.ldap_version; -+#endif -+ debug3 ("LDAP set version to %d", options.ldap_version); -+ -+#if LDAP_SET_REBIND_PROC_ARGS == 3 -+ ldap_set_rebind_proc (ld, _rebind_proc, NULL); -+#elif LDAP_SET_REBIND_PROC_ARGS == 2 -+ ldap_set_rebind_proc (ld, _rebind_proc); -+#else -+#warning unknown LDAP_SET_REBIND_PROC_ARGS -+#endif -+ debug3 ("LDAP set rebind proc"); -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF) -+ (void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref); -+#else -+ ld->ld_deref = options.deref; -+#endif -+ debug3 ("LDAP set deref to %d", options.deref); -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT) -+ (void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT, -+ &options.timelimit); -+#else -+ ld->ld_timelimit = options.timelimit; -+#endif -+ debug3 ("LDAP set timelimit to %d", options.timelimit); -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT) -+ /* -+ * This is a new option in the Netscape SDK which sets -+ * the TCP connect timeout. For want of a better value, -+ * we use the bind_timelimit to control this. -+ */ -+ timeout = options.bind_timelimit * 1000; -+ (void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout); -+ debug3 ("LDAP set opt connect timeout to %d", timeout); -+#endif -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT) -+ tv.tv_sec = options.bind_timelimit; -+ tv.tv_usec = 0; -+ (void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); -+ debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec); -+#endif -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS) -+ (void) ldap_set_option (ld, LDAP_OPT_REFERRALS, -+ options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF); -+ debug3 ("LDAP set referrals to %d", options.referrals); -+#endif -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART) -+ (void) ldap_set_option (ld, LDAP_OPT_RESTART, -+ options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF); -+ debug3 ("LDAP set restart to %d", options.restart); -+#endif -+ -+#ifdef HAVE_LDAP_START_TLS_S -+ if (options.ssl == SSL_START_TLS) { -+ int version; -+ -+ if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version) -+ == LDAP_SUCCESS) { -+ if (version < LDAP_VERSION3) { -+ version = LDAP_VERSION3; -+ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, -+ &version); -+ debug3 ("LDAP set version to %d", version); -+ } -+ } -+ -+ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) -+ fatal ("ldap_starttls_s: %s", ldap_err2string (rc)); -+ debug3 ("LDAP start TLS"); -+ } -+#endif /* HAVE_LDAP_START_TLS_S */ -+ } -+ -+ if ((msgid = ldap_simple_bind (ld, options.binddn, -+ options.bindpw)) == -1) { -+ ld_errno = ldap_get_lderrno (ld, 0, 0); -+ -+ error ("ldap_simple_bind %s", ldap_err2string (ld_errno)); -+ reconnect++; -+ goto retry; -+ } -+ debug3 ("LDAP simple bind (%s)", options.binddn); -+ -+ timeout.tv_sec = options.bind_timelimit; -+ timeout.tv_usec = 0; -+ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { -+ ld_errno = ldap_get_lderrno (ld, 0, 0); -+ -+ error ("ldap_result %s", ldap_err2string (ld_errno)); -+ reconnect++; -+ goto retry; -+ } -+ debug3 ("LDAP result in time"); -+ -+#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) -+ controls = NULL; -+ if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS) -+ fatal ("ldap_parse_result %s", ldap_err2string (parserc)); -+ debug3 ("LDAP parse result OK"); -+ -+ if (controls != NULL) { -+ ldap_controls_free (controls); -+ } -+#else -+ rc = ldap_result2error (session->ld, result, TRUE); -+#endif -+ if (rc != LDAP_SUCCESS) -+ fatal ("error trying to bind as user \"%s\" (%s)", -+ options.binddn, ldap_err2string (rc)); -+ -+ debug2 ("LDAP do connect OK"); -+} -+ -+void -+process_user (const char *user, FILE *output) -+{ -+ LDAPMessage *res, *e; -+ char *buffer; -+ int bufflen, rc, i; -+ struct timeval timeout; -+ -+ debug ("LDAP process user"); -+ -+ /* quick check for attempts to be evil */ -+ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) || -+ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) { -+ logit ("illegal user name %s not processed", user); -+ return; -+ } -+ -+ /* build filter for LDAP request */ -+ bufflen = strlen (LDAPSEARCH_FORMAT) + strlen (user); -+ if (options.ssh_filter != NULL) -+ bufflen += strlen (options.ssh_filter); -+ buffer = xmalloc (bufflen); -+ snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, user, (options.ssh_filter != NULL) ? options.ssh_filter : NULL); -+ buffer[bufflen - 1] = 0; -+ -+ debug3 ("LDAP search scope = %d %s", options.scope, buffer); -+ -+ timeout.tv_sec = options.timelimit; -+ timeout.tv_usec = 0; -+ if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) { -+ error ("ldap_search_st(): %s", ldap_err2string (rc)); -+ xfree (buffer); -+ return; -+ } -+ -+ /* free */ -+ xfree (buffer); -+ -+ for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) { -+ int num; -+ struct berval **keys; -+ -+ keys = ldap_get_values_len(ld, e, PUBKEYATTR); -+ num = ldap_count_values_len(keys); -+ for (i = 0 ; i < num ; i++) { -+ char *cp; //, *options = NULL; -+ -+ for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++); -+ if (!*cp || *cp == '\n' || *cp == '#') -+ continue; -+ -+ /* We have found the desired key. */ -+ fprintf (output, "%s\n", keys[i]->bv_val); -+ } -+ -+ ldap_value_free_len(keys); -+ } -+ -+ ldap_msgfree(res); -+ debug2 ("LDAP process user finished"); -+} -+ -+void -+ldap_do_close(void) -+{ -+ int rc; -+ -+ debug ("LDAP do close"); -+ if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS) -+ fatal ("ldap_unbind_ext: %s", -+ ldap_err2string (rc)); -+ -+ ld = NULL; -+ debug2 ("LDAP do close OK"); -+ return; -+} -+ -diff -up openssh-5.5p1/ldapbody.h.ldap openssh-5.5p1/ldapbody.h ---- openssh-5.5p1/ldapbody.h.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapbody.h 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,37 @@ -+/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef LDAPBODY_H -+#define LDAPBODY_H -+ -+#include -+ -+void ldap_checkconfig(void); -+void ldap_do_connect(void); -+void process_user(const char *, FILE *); -+void ldap_do_close(void); -+ -+#endif /* LDAPBODY_H */ -+ -diff -up openssh-5.5p1/ldapconf.c.ldap openssh-5.5p1/ldapconf.c ---- openssh-5.5p1/ldapconf.c.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapconf.c 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,682 @@ -+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "ldapincludes.h" -+#include "ldap-helper.h" -+#include "log.h" -+#include "misc.h" -+#include "xmalloc.h" -+#include "ldapconf.h" -+#include -+#include -+ -+/* Keyword tokens. */ -+ -+typedef enum { -+ lBadOption, -+ lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN, -+ lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit, -+ lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals, -+ lRestart, lTLS_CheckPeer, lTLS_CaCertFile, -+ lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key, -+ lTLS_RandFile, lLogDir, lDebug, lSSH_Filter, -+ lDeprecated, lUnsupported -+} OpCodes; -+ -+/* Textual representations of the tokens. */ -+ -+static struct { -+ const char *name; -+ OpCodes opcode; -+} keywords[] = { -+ { "URI", lURI }, -+ { "Base", lBase }, -+ { "BindDN", lBindDN }, -+ { "BindPW", lBindPW }, -+ { "RootBindDN", lRootBindDN }, -+ { "Host", lHost }, -+ { "Port", lPort }, -+ { "Scope", lScope }, -+ { "Deref", lDeref }, -+ { "TimeLimit", lTimeLimit }, -+ { "TimeOut", lTimeLimit }, -+ { "Bind_Timelimit", lBind_TimeLimit }, -+ { "Network_TimeOut", lBind_TimeLimit }, -+/* -+ * Todo -+ * SIZELIMIT -+ */ -+ { "Ldap_Version", lLdap_Version }, -+ { "Version", lLdap_Version }, -+ { "Bind_Policy", lBind_Policy }, -+ { "SSLPath", lSSLPath }, -+ { "SSL", lSSL }, -+ { "Referrals", lReferrals }, -+ { "Restart", lRestart }, -+ { "TLS_CheckPeer", lTLS_CheckPeer }, -+ { "TLS_ReqCert", lTLS_CheckPeer }, -+ { "TLS_CaCertFile", lTLS_CaCertFile }, -+ { "TLS_CaCert", lTLS_CaCertFile }, -+ { "TLS_CaCertDir", lTLS_CaCertDir }, -+ { "TLS_Ciphers", lTLS_Ciphers }, -+ { "TLS_Cipher_Suite", lTLS_Ciphers }, -+ { "TLS_Cert", lTLS_Cert }, -+ { "TLS_Certificate", lTLS_Cert }, -+ { "TLS_Key", lTLS_Key }, -+ { "TLS_RandFile", lTLS_RandFile }, -+/* -+ * Todo -+ * TLS_CRLCHECK -+ * TLS_CRLFILE -+ */ -+ { "LogDir", lLogDir }, -+ { "Debug", lDebug }, -+ { "SSH_Filter", lSSH_Filter }, -+ { NULL, lBadOption } -+}; -+ -+/* Configuration ptions. */ -+ -+Options options; -+ -+/* -+ * Returns the number of the token pointed to by cp or oBadOption. -+ */ -+ -+static OpCodes -+parse_token(const char *cp, const char *filename, int linenum) -+{ -+ u_int i; -+ -+ for (i = 0; keywords[i].name; i++) -+ if (strcasecmp(cp, keywords[i].name) == 0) -+ return keywords[i].opcode; -+ -+ if (config_warning_config_file) -+ logit("%s: line %d: Bad configuration option: %s", -+ filename, linenum, cp); -+ return lBadOption; -+} -+ -+/* -+ * Processes a single option line as used in the configuration files. This -+ * only sets those values that have not already been set. -+ */ -+#define WHITESPACE " \t\r\n" -+ -+static int -+process_config_line(char *line, const char *filename, int linenum) -+{ -+ char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg; -+ char *rootbinddn = NULL; -+ int opcode, *intptr, value; -+ size_t len; -+ -+ /* Strip trailing whitespace */ -+ for (len = strlen(line) - 1; len > 0; len--) { -+ if (strchr(WHITESPACE, line[len]) == NULL) -+ break; -+ line[len] = '\0'; -+ } -+ -+ s = line; -+ /* Get the keyword. (Each line is supposed to begin with a keyword). */ -+ if ((keyword = strdelim(&s)) == NULL) -+ return 0; -+ /* Ignore leading whitespace. */ -+ if (*keyword == '\0') -+ keyword = strdelim(&s); -+ if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') -+ return 0; -+ -+ opcode = parse_token(keyword, filename, linenum); -+ -+ switch (opcode) { -+ case lBadOption: -+ /* don't panic, but count bad options */ -+ return -1; -+ /* NOTREACHED */ -+ -+ case lHost: -+ xstringptr = &options.host; -+parse_xstring: -+ if (!s || *s == '\0') -+ fatal("%s line %d: missing dn",filename,linenum); -+ if (*xstringptr == NULL) -+ *xstringptr = xstrdup(s); -+ return 0; -+ -+ case lURI: -+ xstringptr = &options.uri; -+ goto parse_xstring; -+ -+ case lBase: -+ xstringptr = &options.base; -+ goto parse_xstring; -+ -+ case lBindDN: -+ xstringptr = &options.binddn; -+ goto parse_xstring; -+ -+ case lBindPW: -+ charptr = &options.bindpw; -+parse_string: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", filename, linenum); -+ if (*charptr == NULL) -+ *charptr = xstrdup(arg); -+ break; -+ -+ case lRootBindDN: -+ xstringptr = &rootbinddn; -+ goto parse_xstring; -+ -+ case lScope: -+ intptr = &options.scope; -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (strcasecmp (arg, "sub") == 0 || strcasecmp (arg, "subtree") == 0) -+ value = LDAP_SCOPE_SUBTREE; -+ else if (strcasecmp (arg, "one") == 0) -+ value = LDAP_SCOPE_ONELEVEL; -+ else if (strcasecmp (arg, "base") == 0) -+ value = LDAP_SCOPE_BASE; -+ else -+ fatal("%.200s line %d: Bad sub/one/base argument.", filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lDeref: -+ intptr = &options.scope; -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing never/searching/finding/always argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (!strcasecmp (arg, "never")) -+ value = LDAP_DEREF_NEVER; -+ else if (!strcasecmp (arg, "searching")) -+ value = LDAP_DEREF_SEARCHING; -+ else if (!strcasecmp (arg, "finding")) -+ value = LDAP_DEREF_FINDING; -+ else if (!strcasecmp (arg, "always")) -+ value = LDAP_DEREF_ALWAYS; -+ else -+ fatal("%.200s line %d: Bad never/searching/finding/always argument.", filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lPort: -+ intptr = &options.port; -+parse_int: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", filename, linenum); -+ if (arg[0] < '0' || arg[0] > '9') -+ fatal("%.200s line %d: Bad number.", filename, linenum); -+ -+ /* Octal, decimal, or hex format? */ -+ value = strtol(arg, &endofnumber, 0); -+ if (arg == endofnumber) -+ fatal("%.200s line %d: Bad number.", filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lTimeLimit: -+ intptr = &options.timelimit; -+parse_time: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%s line %d: missing time value.", -+ filename, linenum); -+ if ((value = convtime(arg)) == -1) -+ fatal("%s line %d: invalid time value.", -+ filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lBind_TimeLimit: -+ intptr = &options.bind_timelimit; -+ goto parse_time; -+ -+ case lLdap_Version: -+ intptr = &options.ldap_version; -+ goto parse_int; -+ -+ case lBind_Policy: -+ intptr = &options.bind_policy; -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "hard_open") == 0 || strcasecmp(arg, "hard_init") == 0) -+ value = 1; -+ else if (strcasecmp(arg, "soft") == 0) -+ value = 0; -+ else -+ fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum); -+ if (*intptr == -1) -+ break; -+ -+ case lSSLPath: -+ charptr = &options.sslpath; -+ goto parse_string; -+ -+ case lSSL: -+ intptr = &options.ssl; -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing yes/no/start_tls argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) -+ value = SSL_LDAPS; -+ else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) -+ value = SSL_OFF; -+ else if (!strcasecmp (arg, "start_tls")) -+ value = SSL_START_TLS; -+ else -+ fatal("%.200s line %d: Bad yes/no/start_tls argument.", filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lReferrals: -+ intptr = &options.referrals; -+parse_flag: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) -+ value = 1; -+ else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) -+ value = 0; -+ else -+ fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); -+ if (*intptr == -1) -+ *intptr = value; -+ break; -+ -+ case lRestart: -+ intptr = &options.restart; -+ goto parse_flag; -+ -+ case lTLS_CheckPeer: -+ intptr = &options.tls_checkpeer; -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", filename, linenum); -+ value = 0; /* To avoid compiler warning... */ -+ if (strcasecmp(arg, "never") == 0 || strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) -+ value = LDAP_OPT_X_TLS_NEVER; -+ else if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) -+ value = LDAP_OPT_X_TLS_HARD; -+ else if (strcasecmp(arg, "demand") == 0) -+ value = LDAP_OPT_X_TLS_DEMAND; -+ else if (strcasecmp(arg, "allow") == 0) -+ value = LDAP_OPT_X_TLS_ALLOW; -+ else if (strcasecmp(arg, "try") == 0) -+ value = LDAP_OPT_X_TLS_TRY; -+ else -+ fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum); -+ if (*intptr == -1) -+ break; -+ -+ case lTLS_CaCertFile: -+ charptr = &options.tls_cacertfile; -+ goto parse_string; -+ -+ case lTLS_CaCertDir: -+ charptr = &options.tls_cacertdir; -+ goto parse_string; -+ -+ case lTLS_Ciphers: -+ xstringptr = &options.tls_ciphers; -+ goto parse_xstring; -+ -+ case lTLS_Cert: -+ charptr = &options.tls_cert; -+ goto parse_string; -+ -+ case lTLS_Key: -+ charptr = &options.tls_key; -+ goto parse_string; -+ -+ case lTLS_RandFile: -+ charptr = &options.tls_randfile; -+ goto parse_string; -+ -+ case lLogDir: -+ charptr = &options.logdir; -+ goto parse_string; -+ -+ case lDebug: -+ intptr = &options.debug; -+ goto parse_int; -+ -+ case lSSH_Filter: -+ xstringptr = &options.ssh_filter; -+ goto parse_xstring; -+ -+ case lDeprecated: -+ debug("%s line %d: Deprecated option \"%s\"", -+ filename, linenum, keyword); -+ return 0; -+ -+ case lUnsupported: -+ error("%s line %d: Unsupported option \"%s\"", -+ filename, linenum, keyword); -+ return 0; -+ -+ default: -+ fatal("process_config_line: Unimplemented opcode %d", opcode); -+ } -+ -+ /* Check that there is no garbage at end of line. */ -+ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { -+ fatal("%.200s line %d: garbage at end of line; \"%.200s\".", -+ filename, linenum, arg); -+ } -+ return 0; -+} -+ -+/* -+ * Reads the config file and modifies the options accordingly. Options -+ * should already be initialized before this call. This never returns if -+ * there is an error. If the file does not exist, this returns 0. -+ */ -+ -+void -+read_config_file(const char *filename) -+{ -+ FILE *f; -+ char line[1024]; -+ int active, linenum; -+ int bad_options = 0; -+ struct stat sb; -+ -+ if ((f = fopen(filename, "r")) == NULL) -+ fatal("fopen %s: %s", filename, strerror(errno)); -+ -+ if (fstat(fileno(f), &sb) == -1) -+ fatal("fstat %s: %s", filename, strerror(errno)); -+ if (((sb.st_uid != 0 && sb.st_uid != getuid()) || -+ (sb.st_mode & 022) != 0)) -+ fatal("Bad owner or permissions on %s", filename); -+ -+ debug("Reading configuration data %.200s", filename); -+ -+ /* -+ * Mark that we are now processing the options. This flag is turned -+ * on/off by Host specifications. -+ */ -+ active = 1; -+ linenum = 0; -+ while (fgets(line, sizeof(line), f)) { -+ /* Update line number counter. */ -+ linenum++; -+ if (process_config_line(line, filename, linenum) != 0) -+ bad_options++; -+ } -+ fclose(f); -+ if ((bad_options > 0) && config_exclusive_config_file) -+ fatal("%s: terminating, %d bad configuration options", -+ filename, bad_options); -+} -+ -+/* -+ * Initializes options to special values that indicate that they have not yet -+ * been set. Read_config_file will only set options with this value. Options -+ * are processed in the following order: command line, user config file, -+ * system config file. Last, fill_default_options is called. -+ */ -+ -+void -+initialize_options(void) -+{ -+ memset(&options, 'X', sizeof(options)); -+ options.host = NULL; -+ options.uri = NULL; -+ options.base = NULL; -+ options.binddn = NULL; -+ options.bindpw = NULL; -+ options.scope = -1; -+ options.deref = -1; -+ options.port = -1; -+ options.timelimit = -1; -+ options.bind_timelimit = -1; -+ options.ldap_version = -1; -+ options.bind_policy = -1; -+ options.sslpath = NULL; -+ options.ssl = -1; -+ options.referrals = -1; -+ options.restart = -1; -+ options.tls_checkpeer = -1; -+ options.tls_cacertfile = NULL; -+ options.tls_cacertdir = NULL; -+ options.tls_ciphers = NULL; -+ options.tls_cert = NULL; -+ options.tls_key = NULL; -+ options.tls_randfile = NULL; -+ options.logdir = NULL; -+ options.debug = -1; -+ options.ssh_filter = NULL; -+} -+ -+/* -+ * Called after processing other sources of option data, this fills those -+ * options for which no value has been specified with their default values. -+ */ -+ -+void -+fill_default_options(void) -+{ -+ if (options.uri != NULL) { -+ LDAPURLDesc *ludp; -+ -+ if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) { -+ if (options.ssl == -1) { -+ if (strcmp (ludp->lud_scheme, "ldap") == 0) -+ options.ssl = 2; -+ if (strcmp (ludp->lud_scheme, "ldapi") == 0) -+ options.ssl = 0; -+ else if (strcmp (ludp->lud_scheme, "ldaps") == 0) -+ options.ssl = 1; -+ } -+ if (options.host == NULL) -+ options.host = xstrdup (ludp->lud_host); -+ if (options.port == -1) -+ options.port = ludp->lud_port; -+ -+ ldap_free_urldesc (ludp); -+ } -+ } -+ if (options.ssl == -1) -+ options.ssl = SSL_START_TLS; -+ if (options.port == -1) -+ options.port = (options.ssl == 0) ? 389 : 636; -+ if (options.uri == NULL) { -+ int len; -+#define MAXURILEN 4096 -+ -+ options.uri = xmalloc (MAXURILEN); -+ len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d", -+ (options.ssl == 0) ? "" : "s", options.host, options.port); -+ options.uri[MAXURILEN - 1] = 0; -+ options.uri = xrealloc (options.uri, len + 1, 1); -+ } -+ if (options.binddn == NULL) -+ options.binddn = ""; -+ if (options.bindpw == NULL) -+ options.bindpw = ""; -+ if (options.scope == -1) -+ options.scope = LDAP_SCOPE_SUBTREE; -+ if (options.deref == -1) -+ options.deref = LDAP_DEREF_NEVER; -+ if (options.timelimit == -1) -+ options.timelimit = 10; -+ if (options.bind_timelimit == -1) -+ options.bind_timelimit = 10; -+ if (options.ldap_version == -1) -+ options.ldap_version = 3; -+ if (options.bind_policy == -1) -+ options.bind_policy = 1; -+ if (options.referrals == -1) -+ options.referrals = 1; -+ if (options.restart == -1) -+ options.restart = 1; -+ if (options.tls_checkpeer == -1) -+ options.tls_checkpeer = LDAP_OPT_X_TLS_HARD; -+ if (options.debug == -1) -+ options.debug = 0; -+ if (options.ssh_filter == NULL) -+ options.ssh_filter = ""; -+} -+ -+static const char * -+lookup_opcode_name(OpCodes code) -+{ -+ u_int i; -+ -+ for (i = 0; keywords[i].name != NULL; i++) -+ if (keywords[i].opcode == code) -+ return(keywords[i].name); -+ return "UNKNOWN"; -+} -+ -+static void -+dump_cfg_string(OpCodes code, const char *val) -+{ -+ if (val == NULL) -+ debug3("%s ", lookup_opcode_name(code)); -+ else -+ debug3("%s %s", lookup_opcode_name(code), val); -+} -+ -+static void -+dump_cfg_int(OpCodes code, int val) -+{ -+ if (val == -1) -+ debug3("%s ", lookup_opcode_name(code)); -+ else -+ debug3("%s %d", lookup_opcode_name(code), val); -+} -+ -+struct names { -+ int value; -+ char *name; -+}; -+ -+static void -+dump_cfg_namedint(OpCodes code, int val, struct names *names) -+{ -+ u_int i; -+ -+ if (val == -1) -+ debug3("%s ", lookup_opcode_name(code)); -+ else { -+ for (i = 0; names[i].value != -1; i++) -+ if (names[i].value == val) { -+ debug3("%s %s", lookup_opcode_name(code), names[i].name); -+ return; -+ } -+ debug3("%s unknown: %d", lookup_opcode_name(code), val); -+ } -+} -+ -+static struct names _yesnotls[] = { -+ { 0, "No" }, -+ { 1, "Yes" }, -+ { 2, "Start_TLS" }, -+ { -1, NULL }}; -+ -+static struct names _scope[] = { -+ { LDAP_SCOPE_BASE, "Base" }, -+ { LDAP_SCOPE_ONELEVEL, "One" }, -+ { LDAP_SCOPE_SUBTREE, "Sub"}, -+ { -1, NULL }}; -+ -+static struct names _deref[] = { -+ { LDAP_DEREF_NEVER, "Never" }, -+ { LDAP_DEREF_SEARCHING, "Searching" }, -+ { LDAP_DEREF_FINDING, "Finding" }, -+ { LDAP_DEREF_ALWAYS, "Always" }, -+ { -1, NULL }}; -+ -+static struct names _yesno[] = { -+ { 0, "No" }, -+ { 1, "Yes" }, -+ { -1, NULL }}; -+ -+static struct names _bindpolicy[] = { -+ { 0, "Soft" }, -+ { 1, "Hard" }, -+ { -1, NULL }}; -+ -+static struct names _checkpeer[] = { -+ { LDAP_OPT_X_TLS_NEVER, "Never" }, -+ { LDAP_OPT_X_TLS_HARD, "Hard" }, -+ { LDAP_OPT_X_TLS_DEMAND, "Demand" }, -+ { LDAP_OPT_X_TLS_ALLOW, "Allow" }, -+ { LDAP_OPT_X_TLS_TRY, "TRY" }, -+ { -1, NULL }}; -+ -+void -+dump_config(void) -+{ -+ dump_cfg_string(lURI, options.uri); -+ dump_cfg_string(lHost, options.host); -+ dump_cfg_int(lPort, options.port); -+ dump_cfg_namedint(lSSL, options.ssl, _yesnotls); -+ dump_cfg_int(lLdap_Version, options.ldap_version); -+ dump_cfg_int(lTimeLimit, options.timelimit); -+ dump_cfg_int(lBind_TimeLimit, options.bind_timelimit); -+ dump_cfg_string(lBase, options.base); -+ dump_cfg_string(lBindDN, options.binddn); -+ dump_cfg_string(lBindPW, options.bindpw); -+ dump_cfg_namedint(lScope, options.scope, _scope); -+ dump_cfg_namedint(lDeref, options.deref, _deref); -+ dump_cfg_namedint(lReferrals, options.referrals, _yesno); -+ dump_cfg_namedint(lRestart, options.restart, _yesno); -+ dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy); -+ dump_cfg_string(lSSLPath, options.sslpath); -+ dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer); -+ dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile); -+ dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir); -+ dump_cfg_string(lTLS_Ciphers, options.tls_ciphers); -+ dump_cfg_string(lTLS_Cert, options.tls_cert); -+ dump_cfg_string(lTLS_Key, options.tls_key); -+ dump_cfg_string(lTLS_RandFile, options.tls_randfile); -+ dump_cfg_string(lLogDir, options.logdir); -+ dump_cfg_int(lDebug, options.debug); -+ dump_cfg_string(lSSH_Filter, options.ssh_filter); -+} -+ -diff -up openssh-5.5p1/ldapconf.h.ldap openssh-5.5p1/ldapconf.h ---- openssh-5.5p1/ldapconf.h.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapconf.h 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,71 @@ -+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef LDAPCONF_H -+#define LDAPCONF_H -+ -+#define SSL_OFF 0 -+#define SSL_LDAPS 1 -+#define SSL_START_TLS 2 -+ -+/* Data structure for representing option data. */ -+ -+typedef struct { -+ char *host; -+ char *uri; -+ char *base; -+ char *binddn; -+ char *bindpw; -+ int scope; -+ int deref; -+ int port; -+ int timelimit; -+ int bind_timelimit; -+ int ldap_version; -+ int bind_policy; -+ char *sslpath; -+ int ssl; -+ int referrals; -+ int restart; -+ int tls_checkpeer; -+ char *tls_cacertfile; -+ char *tls_cacertdir; -+ char *tls_ciphers; -+ char *tls_cert; -+ char *tls_key; -+ char *tls_randfile; -+ char *logdir; -+ int debug; -+ char *ssh_filter; -+} Options; -+ -+extern Options options; -+ -+void read_config_file(const char *); -+void initialize_options(void); -+void fill_default_options(void); -+void dump_config(void); -+ -+#endif /* LDAPCONF_H */ -diff -up openssh-5.5p1/ldap.conf.ldap openssh-5.5p1/ldap.conf ---- openssh-5.5p1/ldap.conf.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldap.conf 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,88 @@ -+# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $ -+# -+# This is the example configuration file for the OpenSSH -+# LDAP backend -+# -+# see ssh-ldap.conf(5) -+# -+ -+# URI with your LDAP server name. This allows to use -+# Unix Domain Sockets to connect to a local LDAP Server. -+#uri ldap://127.0.0.1/ -+#uri ldaps://127.0.0.1/ -+#uri ldapi://%2fvar%2frun%2fldapi_sock/ -+# Note: %2f encodes the '/' used as directory separator -+ -+# Another way to specify your LDAP server is to provide an -+# host name and the port of our LDAP server. Host name -+# must be resolvable without using LDAP. -+# Multiple hosts may be specified, each separated by a -+# space. How long nss_ldap takes to failover depends on -+# whether your LDAP client library supports configurable -+# network or connect timeouts (see bind_timelimit). -+#host 127.0.0.1 -+ -+# The port. -+# Optional: default is 389. -+#port 389 -+ -+# The distinguished name to bind to the server with. -+# Optional: default is to bind anonymously. -+#binddn cn=openssh_keys,dc=example,dc=org -+ -+# The credentials to bind with. -+# Optional: default is no credential. -+#bindpw TopSecret -+ -+# The distinguished name of the search base. -+#base dc=example,dc=org -+ -+# The LDAP version to use (defaults to 3 -+# if supported by client library) -+#ldap_version 3 -+ -+# The search scope. -+#scope sub -+#scope one -+#scope base -+ -+# Search timelimit -+#timelimit 30 -+ -+# Bind/connect timelimit -+#bind_timelimit 30 -+ -+# Reconnect policy: hard (default) will retry connecting to -+# the software with exponential backoff, soft will fail -+# immediately. -+#bind_policy hard -+ -+# SSL setup, may be implied by URI also. -+#ssl no -+#ssl on -+#ssl start_tls -+ -+# OpenLDAP SSL options -+# Require and verify server certificate (yes/no) -+# Default is to use libldap's default behavior, which can be configured in -+# /etc/openldap/ldap.conf using the TLS_REQCERT setting. The default for -+# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes". -+#tls_checkpeer hard -+ -+# CA certificates for server certificate verification -+# At least one of these are required if tls_checkpeer is "yes" -+#tls_cacertfile /etc/ssl/ca.cert -+#tls_cacertdir /etc/pki/tls/certs -+ -+# Seed the PRNG if /dev/urandom is not provided -+#tls_randfile /var/run/egd-pool -+ -+# SSL cipher suite -+# See man ciphers for syntax -+#tls_ciphers TLSv1 -+ -+# Client certificate and key -+# Use these, if your server requires client authentication. -+#tls_cert -+#tls_key -+ -diff -up openssh-5.5p1/ldap-helper.c.ldap openssh-5.5p1/ldap-helper.c ---- openssh-5.5p1/ldap-helper.c.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldap-helper.c 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,154 @@ -+/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "ldapincludes.h" -+#include "log.h" -+#include "misc.h" -+#include "xmalloc.h" -+#include "ldapconf.h" -+#include "ldapbody.h" -+#include -+#include -+ -+static int config_debug = 0; -+int config_exclusive_config_file = 0; -+static char *config_file_name = "/etc/ssh/ldap.conf"; -+static char *config_single_user = NULL; -+static int config_verbose = SYSLOG_LEVEL_VERBOSE; -+int config_warning_config_file = 0; -+extern char *__progname; -+ -+static void -+usage(void) -+{ -+ fprintf(stderr, "usage: %s [options]\n", -+ __progname); -+ fprintf(stderr, "Options:\n"); -+ fprintf(stderr, " -d Output the log messages to stderr.\n"); -+ fprintf(stderr, " -e Check the config file for unknown commands.\n"); -+ fprintf(stderr, " -f file Use alternate config file (default is /etc/ssh/ldap.conf).\n"); -+ fprintf(stderr, " -s user Do not demonize, send the user's key to stdout.\n"); -+ fprintf(stderr, " -v Increase verbosity of the debug output (implies -d).\n"); -+ fprintf(stderr, " -w Warn on unknown commands int the config file.\n"); -+ exit(1); -+} -+ -+/* -+ * Main program for the ssh pka ldap agent. -+ */ -+ -+int -+main(int ac, char **av) -+{ -+ int opt; -+ FILE *outfile = NULL; -+ -+ __progname = ssh_get_progname(av[0]); -+ -+ log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); -+ -+ /* -+ * Initialize option structure to indicate that no values have been -+ * set. -+ */ -+ initialize_options(); -+ -+ /* Parse command-line arguments. */ -+ while ((opt = getopt(ac, av, "def:s:vw")) != -1) { -+ switch (opt) { -+ case 'd': -+ config_debug = 1; -+ break; -+ -+ case 'e': -+ config_exclusive_config_file = 1; -+ config_warning_config_file = 1; -+ break; -+ -+ case 'f': -+ config_file_name = optarg; -+ break; -+ -+ case 's': -+ config_single_user = optarg; -+ outfile = fdopen (dup (fileno (stdout)), "w"); -+ break; -+ -+ case 'v': -+ config_debug = 1; -+ if (config_verbose < SYSLOG_LEVEL_DEBUG3) -+ config_verbose++; -+ break; -+ -+ case 'w': -+ config_warning_config_file = 1; -+ break; -+ -+ case '?': -+ default: -+ usage(); -+ break; -+ } -+ } -+ -+ /* Initialize loging */ -+ log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug); -+ -+ if (ac != optind) -+ fatal ("illegal extra parameter %s", av[1]); -+ -+ /* Ensure that fds 0 and 2 are open or directed to /dev/null */ -+ if (config_debug == 0) -+ sanitise_stdfd(); -+ -+ /* Read config file */ -+ read_config_file(config_file_name); -+ fill_default_options(); -+ if (config_verbose == SYSLOG_LEVEL_DEBUG3) { -+ debug3 ("=== Configuration ==="); -+ dump_config(); -+ debug3 ("=== *** ==="); -+ } -+ -+ ldap_checkconfig(); -+ ldap_do_connect(); -+ -+ if (config_single_user) { -+ process_user (config_single_user, outfile); -+ } else { -+ fatal ("Not yet implemented"); -+/* TODO -+ * open unix socket a run the loop on it -+ */ -+ } -+ -+ ldap_do_close(); -+ return 0; -+} -+ -+/* Ugly hack */ -+void *buffer_get_string(Buffer *b, u_int *l) {} -+void buffer_put_string(Buffer *b, const void *f, u_int l) {} -+ -diff -up openssh-5.5p1/ldap-helper.h.ldap openssh-5.5p1/ldap-helper.h ---- openssh-5.5p1/ldap-helper.h.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldap-helper.h 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,32 @@ -+/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef LDAP_HELPER_H -+#define LDAP_HELPER_H -+ -+extern int config_exclusive_config_file; -+extern int config_warning_config_file; -+ -+#endif /* LDAP_HELPER_H */ -diff -up openssh-5.5p1/ldapincludes.h.ldap openssh-5.5p1/ldapincludes.h ---- openssh-5.5p1/ldapincludes.h.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapincludes.h 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,41 @@ -+/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef LDAPINCLUDES_H -+#define LDAPINCLUDES_H -+ -+#include "includes.h" -+ -+#ifdef HAVE_LBER_H -+#include -+#endif -+#ifdef HAVE_LDAP_H -+#include -+#endif -+#ifdef HAVE_LDAP_SSL_H -+#include -+#endif -+ -+#endif /* LDAPINCLUDES_H */ -diff -up openssh-5.5p1/ldapmisc.c.ldap openssh-5.5p1/ldapmisc.c ---- openssh-5.5p1/ldapmisc.c.ldap 2010-07-07 14:36:34.000000000 +0200 -+++ openssh-5.5p1/ldapmisc.c 2010-07-07 14:36:34.000000000 +0200 -@@ -0,0 +1,79 @@ -+ -+#include "ldapincludes.h" -+#include "ldapmisc.h" -+ -+#ifndef HAVE_LDAP_GET_LDERRNO -+int -+ldap_get_lderrno (LDAP * ld, char **m, char **s) -+{ -+#ifdef HAVE_LDAP_GET_OPTION -+ int rc; -+#endif -+ int lderrno; -+ -+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) -+ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) -+ return rc; -+#else -+ lderrno = ld->ld_errno; -+#endif -+ -+ if (s != NULL) { -+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING) -+ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) -+ return rc; -+#else -+ *s = ld->ld_error; -+#endif -+ } -+ -+ if (m != NULL) { -+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN) -+ if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) -+ return rc; -+#else -+ *m = ld->ld_matched; -+#endif -+ } -+ -+ return lderrno; -+} -+#endif -+ -+#ifndef HAVE_LDAP_SET_LDERRNO -+int -+ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s) -+{ -+#ifdef HAVE_LDAP_SET_OPTION -+ int rc; -+#endif -+ -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) -+ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) -+ return rc; -+#else -+ ld->ld_errno = lderrno; -+#endif -+ -+ if (s != NULL) { -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING) -+ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) -+ return rc; -+#else -+ ld->ld_error = s; -+#endif -+ } -+ -+ if (m != NULL) { -+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN) -+ if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) -+ return rc; -+#else -+ ld->ld_matched = m; -+#endif -+ } -+ -+ return LDAP_SUCCESS; -+} -+#endif -+ -diff -up openssh-5.5p1/ldapmisc.h.ldap openssh-5.5p1/ldapmisc.h ---- openssh-5.5p1/ldapmisc.h.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/ldapmisc.h 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,35 @@ -+/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ -+/* -+ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef LDAPMISC_H -+#define LDAPMISC_H -+ -+#include "ldapincludes.h" -+ -+int ldap_get_lderrno (LDAP *, char **, char **); -+int ldap_set_lderrno (LDAP *, int, const char *, const char *); -+ -+#endif /* LDAPMISC_H */ -+ -diff -up openssh-5.5p1/lpk-user-example.txt.ldap openssh-5.5p1/lpk-user-example.txt ---- openssh-5.5p1/lpk-user-example.txt.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/lpk-user-example.txt 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,117 @@ -+ -+Post to ML -> User Made Quick Install Doc. -+Contribution from John Lane -+ -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -+ -+OpenSSH LDAP keystore Patch -+=========================== -+ -+NOTE: these notes are a transcript of a specific installation -+ they work for me, your specifics may be different! -+ from John Lane March 17th 2005 john@lane.uk.net -+ -+This is a patch to OpenSSH 4.0p1 to allow it to obtain users' public keys -+from their LDAP record as an alternative to ~/.ssh/authorized_keys. -+ -+(Assuming here that necessary build stuff is in $BUILD) -+ -+cd $BUILD/openssh-4.0p1 -+patch -Np1 -i $BUILD/openssh-lpk-4.0p1-0.3.patch -+mkdir -p /var/empty && -+./configure --prefix=/usr --sysconfdir=/etc/ssh \ -+ --libexecdir=/usr/sbin --with-md5-passwords --with-pam \ -+ --with-libs="-lldap" --with-cppflags="-DWITH_LDAP_PUBKEY" -+Now do. -+make && -+make install -+ -+Add the following config to /etc/ssh/ssh_config -+UseLPK yes -+LpkServers ldap://myhost.mydomain.com -+LpkUserDN ou=People,dc=mydomain,dc=com -+ -+We need to tell sshd about the SSL keys during boot, as root's -+environment does not exist at that time. Edit /etc/rc.d/init.d/sshd. -+Change the startup code from this: -+ echo "Starting SSH Server..." -+ loadproc /usr/sbin/sshd -+ ;; -+to this: -+ echo "Starting SSH Server..." -+ LDAPRC="/root/.ldaprc" loadproc /usr/sbin/sshd -+ ;; -+ -+Re-start the sshd daemon: -+/etc/rc.d/init.d/sshd restart -+ -+Install the additional LDAP schema -+cp $BUILD/openssh-lpk-0.2.schema /etc/openldap/schema/openssh.schema -+ -+Now add the openSSH LDAP schema to /etc/openldap/slapd.conf: -+Add the following to the end of the existing block of schema includes -+include /etc/openldap/schema/openssh.schema -+ -+Re-start the LDAP server: -+/etc/rc.d/init.d/slapd restart -+ -+To add one or more public keys to a user, eg "testuser" : -+ldapsearch -x -W -Z -LLL -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D -+"uid=testuser,ou=People,dc=mydomain,dc=com" > /tmp/testuser -+ -+append the following to this /tmp/testuser file -+objectclass: ldapPublicKey -+sshPublicKey: ssh-rsa -+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KS -+qIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z8XwSsuAoR1t86t+5dlI -+7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key -+ -+Then do a modify: -+ldapmodify -x -D "uid=testuser,ou=People,dc=mydomain,dc=com" -W -f -+/tmp/testuser -Z -+Enter LDAP Password: -+modifying entry "uid=testuser,ou=People,dc=mydomain,dc=com" -+And check the modify is ok: -+ldapsearch -x -W -Z -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D -+"uid=testuser,ou=People,dc=mydomain,dc=com" -+Enter LDAP Password: -+# extended LDIF -+# -+# LDAPv3 -+# base with scope sub -+# filter: (objectclass=*) -+# requesting: ALL -+# -+ -+# testuser, People, mydomain.com -+dn: uid=testuser,ou=People,dc=mydomain,dc=com -+uid: testuser -+cn: testuser -+objectClass: account -+objectClass: posixAccount -+objectClass: top -+objectClass: shadowAccount -+objectClass: ldapPublicKey -+shadowLastChange: 12757 -+shadowMax: 99999 -+shadowWarning: 7 -+loginShell: /bin/bash -+uidNumber: 9999 -+gidNumber: 501 -+homeDirectory: /home/testuser -+userPassword:: e1NTSEF9UDgwV1hnM1VjUDRJK0k1YnFiL1d4ZUJObXlZZ3Z3UTU= -+sshPublicKey: ssh-rsa -+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KSqIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z -+8XwSsuAoR1t86t+5dlI7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key -+ -+# search result -+search: 3 -+result: 0 Success -+ -+# numResponses: 2 -+# numEntries: 1 -+ -+Now start a ssh session to user "testuser" from usual ssh client (e.g. -+puTTY). Login should succeed. -+ -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -diff -up openssh-5.5p1/Makefile.in.ldap openssh-5.5p1/Makefile.in ---- openssh-5.5p1/Makefile.in.ldap 2010-03-13 22:41:34.000000000 +0100 -+++ openssh-5.5p1/Makefile.in 2010-07-07 14:36:35.000000000 +0200 -@@ -26,6 +26,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpas - SFTP_SERVER=$(libexecdir)/sftp-server - SSH_KEYSIGN=$(libexecdir)/ssh-keysign - SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper -+SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper - RAND_HELPER=$(libexecdir)/ssh-rand-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ - SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -61,8 +62,9 @@ EXEEXT=@EXEEXT@ - - INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ - INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ -+INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ - --TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) -+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) - - LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ -@@ -74,11 +76,11 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b - monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ - kexgex.o kexdhc.o kexgexc.o msg.o progressmeter.o dns.o \ - entropy.o gss-genr.o umac.o jpake.o schnorr.o \ -- ssh-pkcs11.o -+ ssh-pkcs11.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o \ -- roaming_common.o roaming_client.o -+ roaming_common.o roaming_client.o - - SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ - sshpty.o sshlogin.o servconf.o serverloop.o \ -@@ -91,10 +93,10 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw - auth2-gss.o gss-serv.o gss-serv-krb5.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ -- roaming_common.o roaming_serv.o -+ roaming_common.o roaming_serv.o - --MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out --MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 -+MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out -+MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5 - MANTYPE = @MANTYPE@ - - CONFIGFILES=sshd_config.out ssh_config.out moduli.out -@@ -162,6 +164,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss - ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o - $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) - -+ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o -+ $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) -+ - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o - $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) - -@@ -266,6 +271,9 @@ install-files: - fi - $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) -+ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ -+ $(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ -+ fi - $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) - $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -@@ -285,6 +293,10 @@ install-files: - $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 - $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 - $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 -+ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ -+ $(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \ -+ $(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \ -+ fi - -rm -f $(DESTDIR)$(bindir)/slogin - ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 -@@ -321,6 +333,13 @@ install-sysconf: - else \ - echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ - fi -+ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ -+ if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \ -+ $(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \ -+ else \ -+ echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \ -+ fi ; \ -+ fi - - host-key: ssh-keygen$(EXEEXT) - @if [ -z "$(DESTDIR)" ] ; then \ -@@ -384,6 +403,7 @@ uninstall: - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 -+ -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 - - tests interop-tests: $(TARGETS) -diff -up openssh-5.5p1/openssh-lpk-openldap.schema.ldap openssh-5.5p1/openssh-lpk-openldap.schema ---- openssh-5.5p1/openssh-lpk-openldap.schema.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/openssh-lpk-openldap.schema 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,21 @@ -+# -+# LDAP Public Key Patch schema for use with openssh-ldappubkey -+# useful with PKA-LDAP also -+# -+# Author: Eric AUGE -+# -+# Based on the proposal of : Mark Ruijter -+# -+ -+ -+# octetString SYNTAX -+attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' -+ DESC 'MANDATORY: OpenSSH Public key' -+ EQUALITY octetStringMatch -+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) -+ -+# printableString SYNTAX yes|no -+objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY -+ DESC 'MANDATORY: OpenSSH LPK objectclass' -+ MUST ( sshPublicKey $ uid ) -+ ) -diff -up openssh-5.5p1/openssh-lpk-sun.schema.ldap openssh-5.5p1/openssh-lpk-sun.schema ---- openssh-5.5p1/openssh-lpk-sun.schema.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/openssh-lpk-sun.schema 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,23 @@ -+# -+# LDAP Public Key Patch schema for use with openssh-ldappubkey -+# useful with PKA-LDAP also -+# -+# Author: Eric AUGE -+# -+# Schema for Sun Directory Server. -+# Based on the original schema, modified by Stefan Fischer. -+# -+ -+dn: cn=schema -+ -+# octetString SYNTAX -+attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' -+ DESC 'MANDATORY: OpenSSH Public key' -+ EQUALITY octetStringMatch -+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) -+ -+# printableString SYNTAX yes|no -+objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY -+ DESC 'MANDATORY: OpenSSH LPK objectclass' -+ MUST ( sshPublicKey $ uid ) -+ ) -diff -up openssh-5.5p1/README.lpk.ldap openssh-5.5p1/README.lpk ---- openssh-5.5p1/README.lpk.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/README.lpk 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,274 @@ -+OpenSSH LDAP PUBLIC KEY PATCH -+Copyright (c) 2003 Eric AUGE (eau@phear.org) -+All rights reserved. -+ -+Rewriten by Jan F.�Chadima (jchadima@redhat.com) -+Copyright (c) 2010 Red Hat, Inc. -+The new PKA-LDAP patch is rewritten from the scratch. -+LDAP schema and part of the documentation is based on original -+LPK project (http://code.google.com/p/openssh-lpk), -+copyright (c) 2003 Eric AUGE -+The new openssh configuration is different from the original LPK one. -+ -+Redistribution and use in source and binary forms, with or without -+modification, are permitted provided that the following conditions -+are met: -+1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+3. The name of the author may not be used to endorse or promote products -+ derived from this software without specific prior written permission. -+ -+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+purposes of this patch: -+ -+This patch would help to have authentication centralization policy -+using ssh public key authentication. -+This patch could be an alternative to other "secure" authentication system -+working in a similar way (Kerberos, SecurID, etc...), except the fact -+that it's based on OpenSSH and its public key abilities. -+ -+>> FYI: << -+'uid': means unix accounts existing on the current server -+'ServerGroup:' mean server group configured on the current server by the SSH_Filter option in the ldap.conf. -+ -+example schema: -+ -+ -+ server1 (uid: eau,rival,toto) (ServerGroup: unix) -+ ___________ / -+ / \ --- - server3 (uid: eau, titi) (ServerGroup: unix) -+ | LDAP Server | \ -+ | eau ,rival | server2 (uid: rival, eau) (ServerGroup: unix) -+ | titi ,toto | -+ | userx,.... | server5 (uid: eau) (ServerGroup: mail) -+ \___________/ \ / -+ ----- - server4 (uid: eau, rival) (no group configured) -+ \ -+ etc... -+ -+- WHAT WE NEED : -+ -+ * configured LDAP server somewhere on the network (i.e. OpenLDAP) -+ * patched sshd (with this patch ;) -+ * LDAP user(/group) entry (look at users.ldif (& groups.ldif)): -+ User entry: -+ - attached to the 'ldapPublicKey' objectclass -+ - attached to the 'posixAccount' objectclass -+ - with a filled 'sshPublicKey' attribute -+ Example: -+ dn: uid=eau,ou=users,dc=cuckoos,dc=net -+ objectclass: top -+ objectclass: person -+ objectclass: organizationalPerson -+ objectclass: posixAccount -+ objectclass: ldapPublicKey -+ description: Eric AUGE Account -+ userPassword: blah -+ cn: Eric AUGE -+ sn: Eric AUGE -+ uid: eau -+ uidNumber: 1034 -+ gidNumber: 1 -+ homeDirectory: /export/home/eau -+ sshPublicKey: ssh-dss AAAAB3... -+ sshPublicKey: ssh-dss AAAAM5... -+ -+ Group entry: -+ - attached to the 'posixGroup' objectclass -+ - with a 'cn' groupname attribute -+ - with multiple 'memberUid' attributes filled with usernames allowed in this group -+ Example: -+ # few members -+ dn: cn=unix,ou=groups,dc=cuckoos,dc=net -+ objectclass: top -+ objectclass: posixGroup -+ description: Unix based servers group -+ cn: unix -+ gidNumber: 1002 -+ memberUid: eau -+ memberUid: user1 -+ memberUid: user2 -+ -+ -+- HOW IT WORKS : -+ -+ * without patch -+ If a user wants to authenticate to log in a server the sshd, will first look for authentication method allowed (RSAauth,kerberos,etc..) -+ and if RSAauth and tickets based auth fails, it will fallback to standard password authentication (if enabled). -+ -+ * with the patch -+ If a user want to authenticate to log in a server, the sshd will first look for auth method including LDAP pubkey, if the ldappubkey options is enabled. -+ It will do an ldapsearch to get the public key directly from the LDAP instead of reading it from the server filesystem. -+ (usually in $HOME/.ssh/authorized_keys) -+ -+ 2 tokens are added to sshd_config : -+ # here is the new patched ldap related tokens -+ AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-helper -s %u -+ AuthorizedKeysCommandRunAs nobody -+ -+ The LDAP configuratin is read from common /etc/ldap.conf configuration file. -+There is also one optional parameter in the LDAP configuration file, SSH_Filter, which is a LDAP filter limiting keys to be searched. -+ -+- HOW TO INSERT A USER/KEY INTO AN LDAP ENTRY -+ -+ * my way (there is plenty :) -+ - create ldif file (i.e. users.ldif) -+ - cat ~/.ssh/id_dsa.pub OR cat ~/.ssh/id_rsa.pub OR cat ~/.ssh/identity.pub -+ - my way in 4 steps : -+ Example: -+ -+ # you add this to the user entry in the LDIF file : -+ [...] -+ objectclass: posixAccount -+ objectclass: ldapPublicKey -+ [...] -+ sshPubliKey: ssh-dss AAAABDh12DDUR2... -+ [...] -+ -+ # insert your entry and you're done :) -+ ldapadd -D balblabla -w bleh < file.ldif -+ -+ all standard options can be present in the 'sshPublicKey' attribute. -+ -+- WHY : -+ -+ Simply because, i was looking for a way to centralize all sysadmins authentication, easily, without completely using LDAP -+ as authentication method (like pam_ldap etc..). -+ -+ After looking into Kerberos, SecurID, and other centralized secure authentications systems, the use of RSA and LDAP to get -+ public key for authentication allows us to control who has access to which server (the user needs an account and to be in 'strongAuthenticationUser' -+ objectclass within LDAP and part of the group the SSH server is in). -+ -+ Passwords update are no longer a nightmare for a server farm (key pair passphrase is stored on each user's box and private key is locally encrypted using his passphrase -+ so each user can change it as much as he wants). -+ -+ Blocking a user account can be done directly from the LDAP (if sshd is using RSAAuth + ldap only). -+ -+- RULES : -+ Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema. -+ and the additionnal lpk.schema. -+ -+ This patch could allow a smooth transition between standard auth (/etc/passwd) and complete LDAP based authentication -+ (pamldap, nss_ldap, etc..). -+ -+ This can be an alternative to other (old?/expensive?) authentication methods (Kerberos/SecurID/..). -+ -+ Referring to schema at the beginning of this file if user 'eau' is only in group 'unix' -+ 'eau' would ONLY access 'server1', 'server2', 'server3' AND 'server4' BUT NOT 'server5'. -+ If you then modify the LDAP 'mail' group entry to add 'memberUid: eau' THEN user 'eau' would be able -+ to log in 'server5' (i hope you got the idea, my english is bad :). -+ -+ Each server's sshd is patched and configured to ask the public key and the group infos in the LDAP -+ server. -+ When you want to allow a new user to have access to the server parc, you just add him an account on -+ your servers, you add his public key into his entry on the LDAP server, it's done. -+ -+ Because sshds are looking public keys into the LDAP directly instead of a file ($HOME/.ssh/authorized_keys). -+ -+ When the user needs to change his passphrase he can do it directly from his workstation by changing -+ his own key set lock passphrase, and all servers are automatically aware. -+ -+ With a CAREFUL LDAP server configuration you could allow a user to add/delete/modify his own entry himself -+ so he can add/modify/delete himself his public key when needed. -+ -+� FLAWS : -+ LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP -+ allow write to users dn, somebody could replace someuser's public key by its own and impersonate some -+ of your users in all your server farm be VERY CAREFUL. -+ -+ MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login -+ as the impersonnated user. -+ -+ If LDAP server is down then, no fallback on passwd auth. -+ -+ the ldap code part has not been well audited yet. -+ -+- LDAP USER ENTRY EXAMPLES (LDIF Format, look in users.ldif) -+ --- CUT HERE --- -+ dn: uid=jdoe,ou=users,dc=foobar,dc=net -+ objectclass: top -+ objectclass: person -+ objectclass: organizationalPerson -+ objectclass: posixAccount -+ objectclass: ldapPublicKey -+ description: My account -+ cn: John Doe -+ sn: John Doe -+ uid: jdoe -+ uidNumber: 100 -+ gidNumber: 100 -+ homeDirectory: /home/jdoe -+ sshPublicKey: ssh-dss AAAAB3NzaC1kc3MAAAEBAOvL8pREUg9wSy/8+hQJ54YF3AXkB0OZrXB.... -+ [...] -+ --- CUT HERE --- -+ -+- LDAP GROUP ENTRY EXAMPLES (LDIF Format, look in groups.ldif) -+ --- CUT HERE --- -+ dn: cn=unix,ou=groups,dc=cuckoos,dc=net -+ objectclass: top -+ objectclass: posixGroup -+ description: Unix based servers group -+ cn: unix -+ gidNumber: 1002 -+ memberUid: jdoe -+ memberUid: user1 -+ memberUid: user2 -+ [...] -+ --- CUT HERE --- -+ -+>> FYI: << -+Multiple 'sshPublicKey' in a user entry are allowed, as well as multiple 'memberUid' attributes in a group entry -+ -+- COMPILING: -+ 1. Apply the patch -+ 2. ./configure --with-your-options --with-ldap=/prefix/to/ldap_libs_and_includes -+ 3. make -+ 4. it's done. -+ -+- BLA : -+ I hope this could help, and i hope to be clear enough,, or give ideas. questions/comments/improvements are welcome. -+ -+- TODO : -+ Possibility to reuse the ssh-ldap-helper. -+ Tune the LDAP part to all possible LDAP configurations. -+ -+- DIFFERENCES FROM ORIGINAL lpk -+ No LDAP code in sshd. -+ Support for various LDAP platforms and configurations. -+ LDAP is configured in separate ldap.conf file. -+ -+- DOCS/LINK : -+ http://pacsec.jp/core05/psj05-barisani-en.pdf -+ http://fritz.potsdam.edu/projects/openssh-lpk/ -+ http://fritz.potsdam.edu/projects/sshgate/ -+ http://dev.inversepath.com/trac/openssh-lpk -+ http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm ) -+ -+- CONTRIBUTORS/IDEAS/GREETS : -+ - Eric AUGE -+ - Andrea Barisani -+ - Falk Siemonsmeier. -+ - Jacob Rief. -+ - Michael Durchgraf. -+ - frederic peters. -+ - Finlay dobbie. -+ - Stefan Fisher. -+ - Robin H. Johnson. -+ - Adrian Bridgett. -+ -+- CONTACT : -+ Jan F. Chadima -+ -diff -up openssh-5.5p1/ssh-ldap.conf.5.ldap openssh-5.5p1/ssh-ldap.conf.5 ---- openssh-5.5p1/ssh-ldap.conf.5.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/ssh-ldap.conf.5 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,373 @@ -+.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $ -+.\" -+.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. -+.\" -+.\" Permission to use, copy, modify, and distribute this software for any -+.\" purpose with or without fee is hereby granted, provided that the above -+.\" copyright notice and this permission notice appear in all copies. -+.\" -+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+.\" -+.Dd $Mdocdate: may 12 2010 $ -+.Dt SSH-LDAP.CONF 5 -+.Os -+.Sh NAME -+.Nm ssh-ldap.conf -+.Nd configuration file for ssh-ldap-helper -+.Sh SYNOPSIS -+.Nm /etc/ssh/ldap.conf -+.Sh DESCRIPTION -+.Xr ssh-ldap-helper 8 -+reads configuration data from -+.Pa /etc/ssh/ldap.conf -+(or the file specified with -+.Fl f -+on the command line). -+The file contains keyword-argument pairs, one per line. -+Lines starting with -+.Ql # -+and empty lines are interpreted as comments. -+.Pp -+The value starts with the first non-blank character after -+the keyword's name, and terminates at the end of the line, -+or at the last sequence of blanks before the end of the line. -+Quoting values that contain blanks -+may be incorrect, as the quotes would become part of the value. -+The possible keywords and their meanings are as follows (note that -+keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive). -+.It Cm URI -+The argument(s) are in the form -+.Pa ldap[si]://[name[:port]] -+and specify the URI(s) of an LDAP server(s) to which the -+.Xr ssh-ldap-helper 8 -+should connect. The URI scheme may be any of -+.Dq ldap , -+.Dq ldaps -+or -+.Dq ldapi , -+which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP -+over IPC (UNIX domain sockets), respectively. -+Each server's name can be specified as a -+domain-style name or an IP address literal. Optionally, the -+server's name can followed by a ':' and the port number the LDAP -+server is listening on. If no port number is provided, the default -+port for the scheme is used (389 for ldap://, 636 for ldaps://). -+For LDAP over IPC, name is the name of the socket, and no port -+is required, nor allowed; note that directory separators must be -+URL-encoded, like any other characters that are special to URLs; -+A space separated list of URIs may be provided. -+There is no default. -+.It Cm Base -+Specifies the default base Distinguished Name (DN) to use when performing ldap operations. -+The base must be specified as a DN in LDAP format. -+There is no default. -+.It Cm BindDN -+Specifies the default BIND DN to use when connecting to the ldap server. -+The bind DN must be specified as a Distinguished Name in LDAP format. -+There is no default. -+.It Cm BindPW -+Specifies the default password to use when connecting to the ldap server via -+.Cm BindDN . -+There is no default. -+.It Cm RootBindDN -+Intentionaly does nothing. Recognized for compatibility reasons. -+.It Cm Host -+The argument(s) specifies the name(s) of an LDAP server(s) to which the -+.Xr ssh-ldap-helper 8 -+should connect. Each server's name can be specified as a -+domain-style name or an IP address and optionally followed by a ':' and -+the port number the ldap server is listening on. A space-separated -+list of hosts may be provided. -+There is no default. -+.Cm Host -+is deprecated in favor of -+.Cm URI . -+.It Cm Port -+Specifies the default port used when connecting to LDAP servers(s). -+The port may be specified as a number. -+The default port is 389 for ldap:// or 636 for ldaps:// respectively. -+.Cm Port -+is deprecated in favor of -+.Cm URI . -+.It Cm Scope -+Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend. -+There are three options (values) that can be assigned to the -+.Cm Scope parameter: -+.Dq base , -+.Dq one -+and -+.Dq subtree . -+Alias for the subtree is -+.Dq sub . -+The value -+.Dq base -+is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!). -+The value -+.Dq one -+is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN. -+The value -+.Dq subtree -+is used to indicate searching of all entries at all levels under and including the specified base DN. -+The default is -+.Dq subtree . -+.It Cm Deref -+Specifies how alias dereferencing is done when performing a search. There are four -+possible values that can be assigned to the -+.Cm Deref -+parameter: -+.Dq never , -+.Dq searching , -+.Dq finding , -+and -+.Dq always . -+The value -+.Dq never -+means that the aliases are never dereferenced. -+The value -+.Dq searching -+means that the aliases are dereferenced in subordinates of the base object, but -+not in locating the base object of the search. -+The value -+.Dq finding -+means that the aliases are only dereferenced when locating the base object of the search. -+The value -+.Dq always -+means that the aliases are dereferenced both in searching and in locating the base object -+of the search. -+The default is -+.Dq never . -+.It Cm TimeLimit -+Specifies a time limit (in seconds) to use when performing searches. -+The number should be a non-negative integer. A -+.Cm TimeLimit -+of zero (0) specifies that the search time is unlimited. Please note that the server -+may still apply any server-side limit on the duration of a search operation. -+The default value is 10. -+.It Cm TimeOut -+Is an aliast to -+.Cm TimeLimit . -+.It Cm Bind_TimeLimit -+Specifies the timeout (in seconds) after which the poll(2)/select(2) -+following a connect(2) returns in case of no activity. -+The default value is 10. -+.It Cm Network_TimeOut -+Is an alias to -+.Cm Bind_TimeLimit . -+.It Cm Ldap_Version -+Specifies what version of the LDAP protocol should be used. -+The allowed values are 2 or 3. The default is 3. -+.It Cm Version -+Is an alias to -+.Cm Ldap_Version . -+.It Cm Bind_Policy -+Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values: -+.Dq hard -+and -+.Dq soft. -+.Dq hard has 2 aliases -+.Dq hard_open -+and -+.Dq hard_init . -+The value -+.Dq hard -+means that reconects that the -+.Xr ssh-ldap-helper 8 -+tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying. -+The value -+.Dq soft -+means that -+.Xr ssh-ldap-helper 8 -+fails immediately when it cannot connect to the LDAP seerver. -+The deault is -+.Dq hard . -+.It Cm SSLPath -+Specifies the path to the X.509 certificate database. -+There is no default. -+.It Cm SSL -+Specifies whether to use SSL/TLS or not. -+There are three allowed values: -+.Dq yes , -+.Dq no -+and -+.Dq start_tls -+Both -+.Dq true -+and -+.Dq on -+are the aliases for -+.Dq yes . -+.Dq false -+and -+.Dq off -+are the aliases for -+.Dq no . -+If -+.Dqstart_tls -+is specified then StartTLS is used rather than raw LDAP over SSL. -+The default for ldap:// is -+.Dq start_tls , -+for ldaps:// -+.Dq yes -+and -+.Dq no -+for the ldapi:// . -+In case of host based configuration the default is -+.Dq start_tls . -+.It Cm Referrals -+Specifies if the client should automatically follow referrals returned -+by LDAP servers. -+The value can be or -+.Dq yes -+or -+.Dq no . -+.Dq true -+and -+.Dq on -+are the aliases for -+.Dq yes . -+.Dq false -+and -+.Dq off -+are the aliases for -+.Dq no . -+The default is yes. -+.It Cm Restart -+Specifies whether the LDAP client library should restart the select(2) system call when interrupted. -+The value can be or -+.Dq yes -+or -+.Dq no . -+.Dq true -+and -+.Dq on -+are the aliases for -+.Dq yes . -+.Dq false -+and -+.Dq off -+are the aliases for -+.Dq no . -+The default is yes. -+.It Cm TLS_CheckPeer -+Specifies what checks to perform on server certificates in a TLS session, -+if any. The value -+can be specified as one of the following keywords: -+.Dq never , -+.Dq hard , -+.Dq demand , -+.Dq allow -+and -+.Dq try . -+.Dq true , -+.Dq on -+and -+.Dq yes -+are aliases for -+.Dq hard . -+.Dq false , -+.Dq off -+and -+.Dq no -+are the aliases for -+.Dq never . -+The value -+.Dq never -+means that the client will not request or check any server certificate. -+The value -+.Dq allow -+means that the server certificate is requested. If no certificate is provided, -+the session proceeds normally. If a bad certificate is provided, it will -+be ignored and the session proceeds normally. -+The value -+.Dq try -+means that the server certificate is requested. If no certificate is provided, -+the session proceeds normally. If a bad certificate is provided, -+the session is immediately terminated. -+The value -+.Dq demand -+means that the server certificate is requested. If no -+certificate is provided, or a bad certificate is provided, the session -+is immediately terminated. -+The value -+.Dq hard -+is the same as -+.Dq demand . -+It requires an SSL connection. In the case of the plain conection the -+session is immediately terminated. -+The default is -+.Dq hard . -+.It Cm TLS_ReqCert -+Is an alias for -+.Cm TLS_CheckPeer . -+.It Cm TLS_CACertFile -+Specifies the file that contains certificates for all of the Certificate -+Authorities the client will recognize. -+There is no default. -+.It Cm TLS_CACert -+Is an alias for -+.Cm TLS_CACertFile . -+.It Cm TLS_CACertDIR -+Specifies the path of a directory that contains Certificate Authority -+certificates in separate individual files. The -+.Cm TLS_CACert -+is always used before -+.Cm TLS_CACertDir . -+The specified directory must be managed with the OpenSSL c_rehash utility. -+There is no default. -+.It Cm TLS_Ciphers -+Specifies acceptable cipher suite and preference order. -+The value should be a cipher specification for OpenSSL, -+e.g., -+.Dq HIGH:MEDIUM:+SSLv2 . -+The default is -+.Dq ALL . -+.It Cm TLS_Cipher_Suite -+Is an alias for -+.Cm TLS_Ciphers . -+.It Cm TLS_Cert -+Specifies the file that contains the client certificate. -+There is no default. -+.It Cm TLS_Certificate -+Is an alias for -+.Cm TLS_Cert . -+.It Cm TLS_Key -+Specifies the file that contains the private key that matches the certificate -+stored in the -+.Cm TLS_Cert -+file. Currently, the private key must not be protected with a password, so -+it is of critical importance that the key file is protected carefully. -+There is no default. -+.It Cm TLS_RandFile -+Specifies the file to obtain random bits from when /dev/[u]random is -+not available. Generally set to the name of the EGD/PRNGD socket. -+The environment variable RANDFILE can also be used to specify the filename. -+There is no default. -+.It Cm LogDir -+Specifies the directory used for logging by the LDAP client library. -+There is no default. -+.It Cm Debug -+Specifies the debug level used for logging by the LDAP client library. -+There is no default. -+.It Cm SSH_Filter -+Specifies the user filter applied on the LDAP serch. -+The default is no filter. -+.Sh FILES -+.Bl -tag -width Ds -+.It Pa /etc/ssh/ldap.conf -+Ldap configuration file for -+.Xr ssh-ldap-helper 8 . -+.Sh "SEE ALSO" -+.Xr ldap.conf 5 , -+.Xr ssh-ldap-helper 8 -+.Sh HISTORY -+.Nm -+first appeared in -+OpenSSH 5.5 + PKA-LDAP . -+.Sh AUTHORS -+.An Jan F. Chadima Aq jchadima@redhat.com -diff -up openssh-5.5p1/ssh-ldap-helper.8.ldap openssh-5.5p1/ssh-ldap-helper.8 ---- openssh-5.5p1/ssh-ldap-helper.8.ldap 2010-07-07 14:36:35.000000000 +0200 -+++ openssh-5.5p1/ssh-ldap-helper.8 2010-07-07 14:36:35.000000000 +0200 -@@ -0,0 +1,78 @@ -+.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ -+.\" -+.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. -+.\" -+.\" Permission to use, copy, modify, and distribute this software for any -+.\" purpose with or without fee is hereby granted, provided that the above -+.\" copyright notice and this permission notice appear in all copies. -+.\" -+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+.\" -+.Dd $Mdocdate: April 29 2010 $ -+.Dt SSH-LDAP-HELPER 8 -+.Os -+.Sh NAME -+.Nm ssh-ldap-helper -+.Nd sshd helper program for ldap support -+.Sh SYNOPSIS -+.Nm ssh-ldap-helper -+.Op Fl devw -+.Op Fl f Ar file -+.Op Fl s Ar user -+.Sh DESCRIPTION -+.Nm -+is used by -+.Xr sshd 1 -+to access keys provided by an LDAP. -+.Nm -+is disabled by default and can only be enabled in the -+sshd configuration file -+.Pa /etc/ssh/sshd_config -+by setting -+.Cm AuthorizedKeysCommand -+to -+.Dq /usr/libexec/ssh-ldap-helper -s %u . -+.Pp -+.Nm -+is not intended to be invoked by the user, but from -+.Xr sshd 8 . -+.Pp -+The options are as follows: -+.Bl -tag -width Ds -+.It Fl d -+Set the debug mode; -+.Nm -+prints all logs to stderr instead of syslog. -+.It Fl e -+Implies \-w; -+.Nm -+halts if it encounters an unknown item in the ldap.conf file. -+.It Fl f -+.Nm -+uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default). -+.It Fl s -+.Nm -+prints out the user's keys to stdout and exits. -+.It Fl v -+Implies \-d; -+increases verbosity. -+.It Fl w -+.Nm -+writes warnings about unknown items in the ldap.conf configuration file. -+ -+.Sh SEE ALSO -+.Xr sshd 8 , -+.Xr sshd_config 5 , -+.Xr ssh-ldap.conf 5 , -+.Sh HISTORY -+.Nm -+first appeared in -+OpenSSH 5.5 + PKA-LDAP . -+.Sh AUTHORS -+.An Jan F. Chadima Aq jchadima@redhat.com diff --git a/openssh-5.5p1-mls.patch b/openssh-5.5p1-mls.patch deleted file mode 100644 index 3c12716..0000000 --- a/openssh-5.5p1-mls.patch +++ /dev/null @@ -1,432 +0,0 @@ -diff -up openssh-5.4p1/configure.ac.mls openssh-5.4p1/configure.ac ---- openssh-5.4p1/configure.ac.mls 2010-03-01 15:24:27.000000000 +0100 -+++ openssh-5.4p1/configure.ac 2010-03-01 15:24:28.000000000 +0100 -@@ -3360,6 +3360,7 @@ AC_ARG_WITH(selinux, - SSHDLIBS="$SSHDLIBS $LIBSELINUX" - LIBS="$LIBS $LIBSELINUX" - AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level) -+ AC_CHECK_FUNCS(setkeycreatecon) - LIBS="$save_LIBS" - fi ] - ) -diff -up openssh-5.4p1/misc.c.mls openssh-5.4p1/misc.c ---- openssh-5.4p1/misc.c.mls 2010-01-10 00:31:12.000000000 +0100 -+++ openssh-5.4p1/misc.c 2010-03-01 15:24:28.000000000 +0100 -@@ -423,6 +423,7 @@ char * - colon(char *cp) - { - int flag = 0; -+ int start = 1; - - if (*cp == ':') /* Leading colon is part of file name. */ - return (0); -@@ -436,8 +437,13 @@ colon(char *cp) - return (cp+1); - if (*cp == ':' && !flag) - return (cp); -- if (*cp == '/') -- return (0); -+ if (start) { -+ /* Slash on beginning or after dots only denotes file name. */ -+ if (*cp == '/') -+ return (0); -+ if (*cp != '.') -+ start = 0; -+ } - } - return (0); - } -diff -up openssh-5.4p1/openbsd-compat/port-linux.c.mls openssh-5.4p1/openbsd-compat/port-linux.c ---- openssh-5.4p1/openbsd-compat/port-linux.c.mls 2010-03-01 15:24:27.000000000 +0100 -+++ openssh-5.4p1/openbsd-compat/port-linux.c 2010-03-01 15:25:50.000000000 +0100 -@@ -35,13 +35,24 @@ - #include "key.h" - #include "hostfile.h" - #include "auth.h" -+#include "xmalloc.h" - - #ifdef WITH_SELINUX - #include - #include -+#include - #include -+#include -+#include -+ -+#ifdef HAVE_LINUX_AUDIT -+#include -+#include -+#endif - - extern Authctxt *the_authctxt; -+extern int inetd_flag; -+extern int rexeced_flag; - - /* Wrapper around is_selinux_enabled() to log its return value once only */ - int -@@ -57,17 +68,173 @@ ssh_selinux_enabled(void) - return (enabled); - } - -+/* Send audit message */ -+static int -+send_audit_message(int success, security_context_t default_context, -+ security_context_t selected_context) -+{ -+ int rc=0; -+#ifdef HAVE_LINUX_AUDIT -+ char *msg = NULL; -+ int audit_fd = audit_open(); -+ security_context_t default_raw=NULL; -+ security_context_t selected_raw=NULL; -+ rc = -1; -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return 0; /* No audit support in kernel */ -+ error("Error connecting to audit system."); -+ return rc; -+ } -+ if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) { -+ error("Error translating default context."); -+ default_raw = NULL; -+ } -+ if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) { -+ error("Error translating selected context."); -+ selected_raw = NULL; -+ } -+ if (asprintf(&msg, "sshd: default-context=%s selected-context=%s", -+ default_raw ? default_raw : (default_context ? default_context: "?"), -+ selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) { -+ error("Error allocating memory."); -+ goto out; -+ } -+ if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE, -+ msg, NULL, NULL, NULL, success) <= 0) { -+ error("Error sending audit message."); -+ goto out; -+ } -+ rc = 0; -+ out: -+ free(msg); -+ freecon(default_raw); -+ freecon(selected_raw); -+ close(audit_fd); -+#endif -+ return rc; -+} -+ -+static int -+mls_range_allowed(security_context_t src, security_context_t dst) -+{ -+ struct av_decision avd; -+ int retval; -+ unsigned int bit = CONTEXT__CONTAINS; -+ -+ debug("%s: src:%s dst:%s", __func__, src, dst); -+ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd); -+ if (retval || ((bit & avd.allowed) != bit)) -+ return 0; -+ -+ return 1; -+} -+ -+static int -+get_user_context(const char *sename, const char *role, const char *lvl, -+ security_context_t *sc) { -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) { -+ /* User may have requested a level completely outside of his -+ allowed range. We get a context just for auditing as the -+ range check below will certainly fail for default context. */ -+#endif -+ if (get_default_context(sename, NULL, sc) != 0) { -+ *sc = NULL; -+ return -1; -+ } -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ } -+#endif -+ if (role != NULL && role[0]) { -+ context_t con; -+ char *type=NULL; -+ if (get_default_type(role, &type) != 0) { -+ error("get_default_type: failed to get default type for '%s'", -+ role); -+ goto out; -+ } -+ con = context_new(*sc); -+ if (!con) { -+ goto out; -+ } -+ context_role_set(con, role); -+ context_type_set(con, type); -+ freecon(*sc); -+ *sc = strdup(context_str(con)); -+ context_free(con); -+ if (!*sc) -+ return -1; -+ } -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (lvl != NULL && lvl[0]) { -+ /* verify that the requested range is obtained */ -+ context_t con; -+ security_context_t obtained_raw; -+ security_context_t requested_raw; -+ con = context_new(*sc); -+ if (!con) { -+ goto out; -+ } -+ context_range_set(con, lvl); -+ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) { -+ context_free(con); -+ goto out; -+ } -+ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) { -+ freecon(obtained_raw); -+ context_free(con); -+ goto out; -+ } -+ -+ debug("get_user_context: obtained context '%s' requested context '%s'", -+ obtained_raw, requested_raw); -+ if (strcmp(obtained_raw, requested_raw)) { -+ /* set the context to the real requested one but fail */ -+ freecon(requested_raw); -+ freecon(obtained_raw); -+ freecon(*sc); -+ *sc = strdup(context_str(con)); -+ context_free(con); -+ return -1; -+ } -+ freecon(requested_raw); -+ freecon(obtained_raw); -+ context_free(con); -+ } -+#endif -+ return 0; -+ out: -+ freecon(*sc); -+ *sc = NULL; -+ return -1; -+} -+ - /* Return the default security context for the given username */ --static security_context_t --ssh_selinux_getctxbyname(char *pwname) -+static int -+ssh_selinux_getctxbyname(char *pwname, -+ security_context_t *default_sc, security_context_t *user_sc) - { -- security_context_t sc = NULL; - char *sename, *lvl; -+ const char *reqlvl = NULL; - char *role = NULL; -- int r = 0; -+ int r = -1; -+ context_t con = NULL; -+ -+ *default_sc = NULL; -+ *user_sc = NULL; -+ if (the_authctxt) { -+ if (the_authctxt->role != NULL) { -+ char *slash; -+ role = xstrdup(the_authctxt->role); -+ if ((slash = strchr(role, '/')) != NULL) { -+ *slash = '\0'; -+ reqlvl = slash + 1; -+ } -+ } -+ } - -- if (the_authctxt) -- role=the_authctxt->role; - #ifdef HAVE_GETSEUSERBYNAME - if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { - sename = NULL; -@@ -75,38 +242,63 @@ ssh_selinux_getctxbyname(char *pwname) - } - #else - sename = pwname; -- lvl = NULL; -+ lvl = ""; - #endif - - if (r == 0) { - #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -- if (role != NULL && role[0]) -- r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc); -- else -- r = get_default_context_with_level(sename, lvl, NULL, &sc); -+ r = get_default_context_with_level(sename, lvl, NULL, default_sc); - #else -- if (role != NULL && role[0]) -- r = get_default_context_with_role(sename, role, NULL, &sc); -- else -- r = get_default_context(sename, NULL, &sc); -+ r = get_default_context(sename, NULL, default_sc); - #endif - } - -- if (r != 0) { -- switch (security_getenforce()) { -- case -1: -- fatal("%s: ssh_selinux_getctxbyname: " -- "security_getenforce() failed", __func__); -- case 0: -- error("%s: Failed to get default SELinux security " -- "context for %s", __func__, pwname); -- break; -- default: -- fatal("%s: Failed to get default SELinux security " -- "context for %s (in enforcing mode)", -- __func__, pwname); -+ if (r == 0) { -+ /* If launched from xinetd, we must use current level */ -+ if (inetd_flag && !rexeced_flag) { -+ security_context_t sshdsc=NULL; -+ -+ if (getcon_raw(&sshdsc) < 0) -+ fatal("failed to allocate security context"); -+ -+ if ((con=context_new(sshdsc)) == NULL) -+ fatal("failed to allocate selinux context"); -+ reqlvl = context_range_get(con); -+ freecon(sshdsc); -+ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) -+ /* we actually don't change level */ -+ reqlvl = ""; -+ -+ debug("%s: current connection level '%s'", __func__, reqlvl); -+ } -+ -+ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) { -+ r = get_user_context(sename, role, reqlvl, user_sc); -+ -+ if (r == 0 && reqlvl != NULL && reqlvl[0]) { -+ security_context_t default_level_sc = *default_sc; -+ if (role != NULL && role[0]) { -+ if (get_user_context(sename, role, lvl, &default_level_sc) < 0) -+ default_level_sc = *default_sc; -+ } -+ /* verify that the requested range is contained in the user range */ -+ if (mls_range_allowed(default_level_sc, *user_sc)) { -+ logit("permit MLS level %s (user range %s)", reqlvl, lvl); -+ } else { -+ r = -1; -+ error("deny MLS level %s (user range %s)", reqlvl, lvl); -+ } -+ if (default_level_sc != *default_sc) -+ freecon(default_level_sc); -+ } -+ } else { -+ *user_sc = *default_sc; - } - } -+ if (r != 0) { -+ error("%s: Failed to get default SELinux security " -+ "context for %s", __func__, pwname); -+ } - - #ifdef HAVE_GETSEUSERBYNAME - if (sename != NULL) -@@ -114,14 +306,20 @@ ssh_selinux_getctxbyname(char *pwname) - if (lvl != NULL) - xfree(lvl); - #endif -+ if (role != NULL) -+ xfree(role); -+ if (con) -+ context_free(con); - -- return (sc); -+ return (r); - } - - /* Set the execution context to the default for the specified user */ - void - ssh_selinux_setup_exec_context(char *pwname) - { -+ int r = 0; -+ security_context_t default_ctx = NULL; - security_context_t user_ctx = NULL; - - if (!ssh_selinux_enabled()) -@@ -129,22 +327,45 @@ ssh_selinux_setup_exec_context(char *pwn - - debug3("%s: setting execution context", __func__); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -- if (setexeccon(user_ctx) != 0) { -+ r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx); -+ if (r >= 0) { -+ r = setexeccon(user_ctx); -+ if (r < 0) { -+ error("%s: Failed to set SELinux execution context %s for %s", -+ __func__, user_ctx, pwname); -+ } -+#ifdef HAVE_SETKEYCREATECON -+ else if (setkeycreatecon(user_ctx) < 0) { -+ error("%s: Failed to set SELinux keyring creation context %s for %s", -+ __func__, user_ctx, pwname); -+ } -+#endif -+ } -+ if (user_ctx == NULL) { -+ user_ctx = default_ctx; -+ } -+ if (r < 0 || user_ctx != default_ctx) { -+ /* audit just the case when user changed a role or there was -+ a failure */ -+ send_audit_message(r >= 0, default_ctx, user_ctx); -+ } -+ if (r < 0) { - switch (security_getenforce()) { - case -1: - fatal("%s: security_getenforce() failed", __func__); - case 0: -- error("%s: Failed to set SELinux execution " -- "context for %s", __func__, pwname); -+ error("%s: SELinux failure. Continuing in permissive mode.", -+ __func__); - break; - default: -- fatal("%s: Failed to set SELinux execution context " -- "for %s (in enforcing mode)", __func__, pwname); -+ fatal("%s: SELinux failure. Aborting connection.", -+ __func__); - } - } -- if (user_ctx != NULL) -+ if (user_ctx != NULL && user_ctx != default_ctx) - freecon(user_ctx); -+ if (default_ctx != NULL) -+ freecon(default_ctx); - - debug3("%s: done", __func__); - } -@@ -162,7 +383,10 @@ ssh_selinux_setup_pty(char *pwname, cons - - debug3("%s: setting TTY context on %s", __func__, tty); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -+ if (getexeccon(&user_ctx) < 0) { -+ error("%s: getexeccon: %s", __func__, strerror(errno)); -+ goto out; -+ } - - /* XXX: should these calls fatal() upon failure in enforcing mode? */ - -diff -up openssh-5.4p1/sshd.c.mls openssh-5.4p1/sshd.c ---- openssh-5.4p1/sshd.c.mls 2010-03-01 15:24:27.000000000 +0100 -+++ openssh-5.4p1/sshd.c 2010-03-01 15:24:28.000000000 +0100 -@@ -1987,6 +1987,9 @@ main(int ac, char **av) - restore_uid(); - } - #endif -+#ifdef WITH_SELINUX -+ ssh_selinux_setup_exec_context(authctxt->pw->pw_name); -+#endif - #ifdef USE_PAM - if (options.use_pam) { - do_pam_setcred(1); diff --git a/openssh-5.5p1-staterr.patch b/openssh-5.5p1-staterr.patch deleted file mode 100644 index ecabf2d..0000000 --- a/openssh-5.5p1-staterr.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff -up openssh-5.5p1/ssh-keygen.c.staterr openssh-5.5p1/ssh-keygen.c ---- openssh-5.5p1/ssh-keygen.c.staterr 2010-05-04 09:01:14.000000000 +0200 -+++ openssh-5.5p1/ssh-keygen.c 2010-05-04 09:03:32.000000000 +0200 -@@ -1831,13 +1831,19 @@ main(int argc, char **argv) - ask_filename(pw, "Enter file in which to save the key"); - - /* Create ~/.ssh directory if it doesn't already exist. */ -- snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); -- if (strstr(identity_file, dotsshdir) != NULL && -- stat(dotsshdir, &st) < 0) { -- if (mkdir(dotsshdir, 0700) < 0) -- error("Could not create directory '%s'.", dotsshdir); -- else if (!quiet) -- printf("Created directory '%s'.\n", dotsshdir); -+ snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", -+ pw->pw_dir, _PATH_SSH_USER_DIR); -+ if (strstr(identity_file, dotsshdir) != NULL) { -+ if (stat(dotsshdir, &st) < 0) { -+ if (errno != ENOENT) { -+ error("Could not stat %s: %s", dotsshdir, -+ strerror(errno)); -+ } else if (mkdir(dotsshdir, 0700) < 0) { -+ error("Could not create directory '%s': %s", -+ dotsshdir, strerror(errno)); -+ } else if (!quiet) -+ printf("Created directory '%s'.\n", dotsshdir); -+ } - } - /* If the file already exists, ask the user to confirm. */ - if (!overwrite && stat(identity_file, &st) >= 0) { diff --git a/openssh-5.5p1-stderr.patch b/openssh-5.5p1-stderr.patch deleted file mode 100644 index 633d30e..0000000 --- a/openssh-5.5p1-stderr.patch +++ /dev/null @@ -1,171 +0,0 @@ -diff -up openssh-5.5p1/channels.c.stderr openssh-5.5p1/channels.c ---- openssh-5.5p1/channels.c.stderr 2010-06-23 15:20:30.000000000 +0200 -+++ openssh-5.5p1/channels.c 2010-06-23 15:23:06.000000000 +0200 -@@ -838,8 +838,9 @@ channel_pre_open(Channel *c, fd_set *rea - if (c->extended_usage == CHAN_EXTENDED_WRITE && - buffer_len(&c->extended) > 0) - FD_SET(c->efd, writeset); -- else if (!(c->flags & CHAN_EOF_SENT) && -- c->extended_usage == CHAN_EXTENDED_READ && -+ else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) && -+ (c->extended_usage == CHAN_EXTENDED_READ || -+ c->extended_usage == CHAN_EXTENDED_IGNORE) && - buffer_len(&c->extended) < c->remote_window) - FD_SET(c->efd, readset); - } -@@ -1759,7 +1760,9 @@ channel_handle_efd(Channel *c, fd_set *r - buffer_consume(&c->extended, len); - c->local_consumed += len; - } -- } else if (c->extended_usage == CHAN_EXTENDED_READ && -+ } else if (c->efd != -1 && -+ (c->extended_usage == CHAN_EXTENDED_READ || -+ c->extended_usage == CHAN_EXTENDED_IGNORE) && - (c->detach_close || FD_ISSET(c->efd, readset))) { - len = read(c->efd, buf, sizeof(buf)); - debug2("channel %d: read %d from efd %d", -@@ -1772,7 +1775,11 @@ channel_handle_efd(Channel *c, fd_set *r - c->self, c->efd); - channel_close_fd(&c->efd); - } else { -- buffer_append(&c->extended, buf, len); -+ if (c->extended_usage == CHAN_EXTENDED_IGNORE) { -+ debug3("channel %d: discard efd", -+ c->self); -+ } else -+ buffer_append(&c->extended, buf, len); - } - } - } -diff -up openssh-5.5p1/session.c.stderr openssh-5.5p1/session.c ---- openssh-5.5p1/session.c.stderr 2010-06-23 15:20:29.000000000 +0200 -+++ openssh-5.5p1/session.c 2010-06-23 15:23:55.000000000 +0200 -@@ -47,6 +47,7 @@ - #include - - #include -+#include - #include - #ifdef HAVE_PATHS_H - #include -@@ -104,7 +105,7 @@ - /* func */ - - Session *session_new(void); --void session_set_fds(Session *, int, int, int, int); -+void session_set_fds(Session *, int, int, int, int, int); - void session_pty_cleanup(Session *); - void session_proctitle(Session *); - int session_setup_x11fwd(Session *); -@@ -443,10 +444,14 @@ int - do_exec_no_pty(Session *s, const char *command) - { - pid_t pid; -+ int ignore_fderr = 0; - - #ifdef USE_PIPES - int pin[2], pout[2], perr[2]; - -+ if (s == NULL) -+ fatal("do_exec_no_pty: no session"); -+ - /* Allocate pipes for communicating with the program. */ - if (pipe(pin) < 0) { - error("%s: pipe in: %.100s", __func__, strerror(errno)); -@@ -459,32 +464,38 @@ do_exec_no_pty(Session *s, const char *c - return -1; - } - if (pipe(perr) < 0) { -- error("%s: pipe err: %.100s", __func__, strerror(errno)); -+ error("%s: pipe err: %.100s", __func__, -+ strerror(errno)); - close(pin[0]); - close(pin[1]); - close(pout[0]); - close(pout[1]); - return -1; - } -+ if (s->is_subsystem) -+ ignore_fderr = 1; - #else - int inout[2], err[2]; - -+ if (s == NULL) -+ fatal("do_exec_no_pty: no session"); -+ - /* Uses socket pairs to communicate with the program. */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { - error("%s: socketpair #1: %.100s", __func__, strerror(errno)); - return -1; - } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { -- error("%s: socketpair #2: %.100s", __func__, strerror(errno)); -+ error("%s: socketpair #2: %.100s", __func__, -+ strerror(errno)); - close(inout[0]); - close(inout[1]); - return -1; - } -+ if (s->is_subsystem) -+ ignore_fderr = 1; - #endif - -- if (s == NULL) -- fatal("do_exec_no_pty: no session"); -- - session_proctitle(s); - - /* Fork the child. */ -@@ -595,11 +606,7 @@ do_exec_no_pty(Session *s, const char *c - close(perr[1]); - - if (compat20) { -- if (s->is_subsystem) { -- close(perr[0]); -- perr[0] = -1; -- } -- session_set_fds(s, pin[1], pout[0], perr[0], 0); -+ session_set_fds(s, pin[1], pout[0], perr[0], ignore_fderr, 0); - } else { - /* Enter the interactive session. */ - server_loop(pid, pin[1], pout[0], perr[0]); -@@ -615,10 +622,7 @@ do_exec_no_pty(Session *s, const char *c - * handle the case that fdin and fdout are the same. - */ - if (compat20) { -- session_set_fds(s, inout[1], inout[1], -- s->is_subsystem ? -1 : err[1], 0); -- if (s->is_subsystem) -- close(err[1]); -+ session_set_fds(s, inout[1], inout[1], err[1], ignore_fderr, 0); - } else { - server_loop(pid, inout[1], inout[1], err[1]); - /* server_loop has closed inout[1] and err[1]. */ -@@ -740,7 +744,7 @@ do_exec_pty(Session *s, const char *comm - s->ptymaster = ptymaster; - packet_set_interactive(1); - if (compat20) { -- session_set_fds(s, ptyfd, fdout, -1, 1); -+ session_set_fds(s, ptyfd, fdout, -1, 1, 1); - } else { - server_loop(pid, ptyfd, fdout, -1); - /* server_loop _has_ closed ptyfd and fdout. */ -@@ -2321,7 +2325,8 @@ session_input_channel_req(Channel *c, co - } - - void --session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty) -+session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, -+ int is_tty) - { - if (!compat20) - fatal("session_set_fds: called for proto != 2.0"); -@@ -2333,7 +2338,7 @@ session_set_fds(Session *s, int fdin, in - fatal("no channel for session %d", s->self); - channel_set_fds(s->chanid, - fdout, fdin, fderr, -- fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, -+ ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, - 1, is_tty, CHAN_SES_WINDOW_DEFAULT); - } - diff --git a/openssh-5.6p1-authorized-keys-command.patch b/openssh-5.6p1-authorized-keys-command.patch new file mode 100644 index 0000000..4c9b5b1 --- /dev/null +++ b/openssh-5.6p1-authorized-keys-command.patch @@ -0,0 +1,447 @@ +diff -up openssh-5.6p1/auth2-pubkey.c.akc openssh-5.6p1/auth2-pubkey.c +--- openssh-5.6p1/auth2-pubkey.c.akc 2010-08-23 12:15:42.000000000 +0200 ++++ openssh-5.6p1/auth2-pubkey.c 2010-08-23 12:15:42.000000000 +0200 +@@ -27,6 +27,7 @@ + + #include + #include ++#include + + #include + #include +@@ -264,27 +265,15 @@ match_principals_file(char *file, struct + + /* return 1 if user allows given key */ + static int +-user_key_allowed2(struct passwd *pw, Key *key, char *file) ++user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw) + { + char line[SSH_MAX_PUBKEY_BYTES]; + const char *reason; + int found_key = 0; +- FILE *f; + u_long linenum = 0; + Key *found; + char *fp; + +- /* Temporarily use the user's uid. */ +- temporarily_use_uid(pw); +- +- debug("trying public key file %s", file); +- f = auth_openkeyfile(file, pw, options.strict_modes); +- +- if (!f) { +- restore_uid(); +- return 0; +- } +- + found_key = 0; + found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); + +@@ -377,8 +366,6 @@ user_key_allowed2(struct passwd *pw, Key + break; + } + } +- restore_uid(); +- fclose(f); + key_free(found); + if (!found_key) + debug2("key not found"); +@@ -440,13 +427,191 @@ user_cert_trusted_ca(struct passwd *pw, + return ret; + } + +-/* check whether given key is in .ssh/authorized_keys* */ ++/* return 1 if user allows given key */ ++static int ++user_key_allowed2(struct passwd *pw, Key *key, char *file) ++{ ++ FILE *f; ++ int found_key = 0; ++ ++ /* Temporarily use the user's uid. */ ++ temporarily_use_uid(pw); ++ ++ debug("trying public key file %s", file); ++ f = auth_openkeyfile(file, pw, options.strict_modes); ++ ++ if (f) { ++ found_key = user_search_key_in_file (f, file, key, pw); ++ fclose(f); ++ } ++ ++ restore_uid(); ++ return found_key; ++} ++ ++#ifdef WITH_AUTHORIZED_KEYS_COMMAND ++ ++#define WHITESPACE " \t\r\n" ++ ++/* return 1 if user allows given key */ ++static int ++user_key_via_command_allowed2(struct passwd *pw, Key *key) ++{ ++ FILE *f; ++ int found_key = 0; ++ char *progname = NULL; ++ char *cp; ++ struct passwd *runas_pw; ++ struct stat st; ++ int childdescriptors[2], i; ++ pid_t pstat, pid, child; ++ ++ if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/') ++ return -1; ++ ++ /* get the run as identity from config */ ++ runas_pw = (options.authorized_keys_command_runas == NULL)? pw ++ : getpwnam (options.authorized_keys_command_runas); ++ if (!runas_pw) { ++ error("%s: getpwnam(\"%s\"): %s", __func__, ++ options.authorized_keys_command_runas, strerror(errno)); ++ return 0; ++ } ++ ++ /* Temporarily use the specified uid. */ ++ if (runas_pw->pw_uid != 0) ++ temporarily_use_uid(runas_pw); ++ ++ progname = xstrdup(options.authorized_keys_command); ++ ++ debug3("%s: checking program '%s'", __func__, progname); ++ ++ if (stat (progname, &st) < 0) { ++ error("%s: stat(\"%s\"): %s", __func__, ++ progname, strerror(errno)); ++ goto go_away; ++ } ++ ++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { ++ error("bad ownership or modes for AuthorizedKeysCommand \"%s\"", ++ progname); ++ goto go_away; ++ } ++ ++ if (!S_ISREG(st.st_mode)) { ++ error("AuthorizedKeysCommand \"%s\" is not a regular file", ++ progname); ++ goto go_away; ++ } ++ ++ /* ++ * Descend the path, checking that each component is a ++ * root-owned directory with strict permissions. ++ */ ++ do { ++ if ((cp = strrchr(progname, '/')) == NULL) ++ break; ++ else ++ *cp = '\0'; ++ ++ debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname)); ++ ++ if (stat((*progname == '\0' ? "/" : progname), &st) != 0) { ++ error("%s: stat(\"%s\"): %s", __func__, ++ progname, strerror(errno)); ++ goto go_away; ++ } ++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { ++ error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"", ++ progname); ++ goto go_away; ++ } ++ if (!S_ISDIR(st.st_mode)) { ++ error("AuthorizedKeysCommand path component \"%s\" is not a directory", ++ progname); ++ goto go_away; ++ } ++ } while (1); ++ ++ /* open the pipe and read the keys */ ++ if (pipe(childdescriptors)) { ++ error("failed to pipe(2) for AuthorizedKeysCommand: %s", ++ strerror(errno)); ++ goto go_away; ++ } ++ ++ child = fork(); ++ if (child == -1) { ++ error("failed to fork(2) for AuthorizedKeysCommand: %s", ++ strerror(errno)); ++ goto go_away; ++ } else if (child == 0) { ++ /* we're in the child process here -- we should never return from this block. */ ++ /* permanently drop privs in child process */ ++ if (runas_pw->pw_uid != 0) { ++ restore_uid(); ++ permanently_set_uid(runas_pw); ++ } ++ ++ close(childdescriptors[0]); ++ /* put the write end of the pipe on stdout (FD 1) */ ++ if (dup2(childdescriptors[1], 1) == -1) { ++ error("failed to dup2(2) from AuthorizedKeysCommand: %s", ++ strerror(errno)); ++ _exit(127); ++ } ++ ++ debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name); ++ /* see session.c:child_close_fds() */ ++ for (i = 3; i < 64; ++i) { ++ close(i); ++ } ++ ++ execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL); ++ ++ /* if we got here, it didn't work */ ++ error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */ ++ _exit(127); ++ } ++ ++ close(childdescriptors[1]); ++ f = fdopen(childdescriptors[0], "r"); ++ if (!f) { ++ error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__, ++ options.authorized_keys_command, strerror (errno)); ++ goto go_away; ++ } ++ ++ found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw); ++ fclose (f); ++ do { ++ pid = waitpid(child, &pstat, 0); ++ } while (pid == -1 && errno == EINTR); ++ ++ /* what about the return value from the child process? */ ++go_away: ++ if (progname) ++ xfree (progname); ++ ++ if (runas_pw->pw_uid != 0) ++ restore_uid(); ++ return found_key; ++} ++#endif ++ ++/* check whether given key is in 0) ++ return success; ++#endif ++ + if (auth_key_is_revoked(key)) + return 0; + if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) +diff -up openssh-5.6p1/configure.ac.akc openssh-5.6p1/configure.ac +--- openssh-5.6p1/configure.ac.akc 2010-08-23 12:15:42.000000000 +0200 ++++ openssh-5.6p1/configure.ac 2010-08-23 12:15:42.000000000 +0200 +@@ -1346,6 +1346,18 @@ AC_ARG_WITH(audit, + esac ] + ) + ++# Check whether user wants AuthorizedKeysCommand support ++AKC_MSG="no" ++AC_ARG_WITH(authorized-keys-command, ++ [ --with-authorized-keys-command Enable AuthorizedKeysCommand support], ++ [ ++ if test "x$withval" != "xno" ; then ++ AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support]) ++ AKC_MSG="yes" ++ fi ++ ] ++) ++ + dnl Checks for library functions. Please keep in alphabetical order + AC_CHECK_FUNCS( \ + arc4random \ +@@ -4209,6 +4221,7 @@ echo " Linux audit support + echo " Smartcard support: $SCARD_MSG" + echo " S/KEY support: $SKEY_MSG" + echo " TCP Wrappers support: $TCPW_MSG" ++echo " AuthorizedKeysCommand support: $AKC_MSG" + echo " MD5 password support: $MD5_MSG" + echo " libedit support: $LIBEDIT_MSG" + echo " Solaris process contract support: $SPC_MSG" +diff -up openssh-5.6p1/servconf.c.akc openssh-5.6p1/servconf.c +--- openssh-5.6p1/servconf.c.akc 2010-08-23 12:15:41.000000000 +0200 ++++ openssh-5.6p1/servconf.c 2010-08-23 12:22:22.000000000 +0200 +@@ -129,6 +129,8 @@ initialize_server_options(ServerOptions + options->num_permitted_opens = -1; + options->adm_forced_command = NULL; + options->chroot_directory = NULL; ++ options->authorized_keys_command = NULL; ++ options->authorized_keys_command_runas = NULL; + options->zero_knowledge_password_authentication = -1; + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; +@@ -316,6 +318,7 @@ typedef enum { + sUsePrivilegeSeparation, sAllowAgentForwarding, + sZeroKnowledgePasswordAuthentication, sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, ++ sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs, + sDeprecated, sUnsupported + } ServerOpCodes; + +@@ -439,6 +442,13 @@ static struct { + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, + { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, ++#ifdef WITH_AUTHORIZED_KEYS_COMMAND ++ { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, ++ { "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL }, ++#else ++ { "authorizedkeyscommand", sUnsupported, SSHCFG_ALL }, ++ { "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL }, ++#endif + { NULL, sBadOption, 0 } + }; + +@@ -1360,6 +1370,20 @@ process_server_config_line(ServerOptions + charptr = &options->revoked_keys_file; + goto parse_filename; + ++ case sAuthorizedKeysCommand: ++ len = strspn(cp, WHITESPACE); ++ if (*activep && options->authorized_keys_command == NULL) ++ options->authorized_keys_command = xstrdup(cp + len); ++ return 0; ++ ++ case sAuthorizedKeysCommandRunAs: ++ charptr = &options->authorized_keys_command_runas; ++ ++ arg = strdelim(&cp); ++ if (*activep && *charptr == NULL) ++ *charptr = xstrdup(arg); ++ break; ++ + case sDeprecated: + logit("%s line %d: Deprecated option %s", + filename, linenum, arg); +@@ -1453,6 +1477,8 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(gss_authentication); + M_CP_INTOPT(rsa_authentication); + M_CP_INTOPT(pubkey_authentication); ++ M_CP_STROPT(authorized_keys_command); ++ M_CP_STROPT(authorized_keys_command_runas); + M_CP_INTOPT(kerberos_authentication); + M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(hostbased_uses_name_from_packet_only); +@@ -1705,6 +1731,8 @@ dump_config(ServerOptions *o) + dump_cfg_string(sRevokedKeys, o->revoked_keys_file); + dump_cfg_string(sAuthorizedPrincipalsFile, + o->authorized_principals_file); ++ dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); ++ dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas); + + /* string arguments requiring a lookup */ + dump_cfg_string(sLogLevel, log_level_name(o->log_level)); +diff -up openssh-5.6p1/servconf.h.akc openssh-5.6p1/servconf.h +--- openssh-5.6p1/servconf.h.akc 2010-08-23 12:15:41.000000000 +0200 ++++ openssh-5.6p1/servconf.h 2010-08-23 12:17:58.000000000 +0200 +@@ -158,6 +158,8 @@ typedef struct { + char *revoked_keys_file; + char *trusted_user_ca_keys; + char *authorized_principals_file; ++ char *authorized_keys_command; ++ char *authorized_keys_command_runas; + } ServerOptions; + + void initialize_server_options(ServerOptions *); +diff -up openssh-5.6p1/sshd_config.0.akc openssh-5.6p1/sshd_config.0 +--- openssh-5.6p1/sshd_config.0.akc 2010-08-23 12:15:41.000000000 +0200 ++++ openssh-5.6p1/sshd_config.0 2010-08-23 12:25:18.000000000 +0200 +@@ -374,7 +374,8 @@ DESCRIPTION + + Only a subset of keywords may be used on the lines following a + Match keyword. Available keywords are AllowAgentForwarding, +- AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile, ++ AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand, ++ AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile, + Banner, ChrootDirectory, ForceCommand, GatewayPorts, + GSSAPIAuthentication, HostbasedAuthentication, + HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication, +@@ -496,6 +497,23 @@ DESCRIPTION + this file is not readable, then public key authentication will be + refused for all users. + ++ AuthorizedKeysCommand ++ ++ Specifies a program to be used for lookup of the user's ++ public keys. The program will be invoked with its first ++ argument the name of the user being authorized, and should produce ++ on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS ++ in sshd(8)). By default (or when set to the empty string) there is no ++ AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully ++ authorize the user, authorization falls through to the ++ AuthorizedKeysFile. Note that this option has an effect ++ only with PubkeyAuthentication turned on. ++ ++ AuthorizedKeysCommandRunAs ++ Specifies the user under whose account the AuthorizedKeysCommand is run. ++ Empty string (the default value) means the user being authorized ++ is used. ++ + RhostsRSAAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication to- + gether with successful RSA host authentication is allowed. The +diff -up openssh-5.6p1/sshd_config.5.akc openssh-5.6p1/sshd_config.5 +--- openssh-5.6p1/sshd_config.5.akc 2010-08-23 12:15:41.000000000 +0200 ++++ openssh-5.6p1/sshd_config.5 2010-08-23 12:25:46.000000000 +0200 +@@ -654,6 +654,8 @@ Available keywords are + .Cm AllowAgentForwarding , + .Cm AllowTcpForwarding , + .Cm AuthorizedKeysFile , ++.Cm AuthorizedKeysCommand , ++.Cm AuthorizedKeysCommandRunAs , + .Cm AuthorizedPrincipalsFile , + .Cm Banner , + .Cm ChrootDirectory , +@@ -666,6 +668,7 @@ Available keywords are + .Cm KerberosAuthentication , + .Cm MaxAuthTries , + .Cm MaxSessions , ++.Cm PubkeyAuthentication , + .Cm PasswordAuthentication , + .Cm PermitEmptyPasswords , + .Cm PermitOpen , +@@ -868,6 +871,20 @@ Specifies a list of revoked public keys. + Keys listed in this file will be refused for public key authentication. + Note that if this file is not readable, then public key authentication will + be refused for all users. ++.It Cm AuthorizedKeysCommand ++Specifies a program to be used for lookup of the user's ++public keys. The program will be invoked with its first ++argument the name of the user being authorized, and should produce ++on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS ++in sshd(8)). By default (or when set to the empty string) there is no ++AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully ++authorize the user, authorization falls through to the ++AuthorizedKeysFile. Note that this option has an effect ++only with PubkeyAuthentication turned on. ++.It Cm AuthorizedKeysCommandRunAs ++Specifies the user under whose account the AuthorizedKeysCommand is run. Empty ++string (the default value) means the user being authorized is used. ++.Dq + .It Cm RhostsRSAAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication together + with successful RSA host authentication is allowed. +diff -up openssh-5.6p1/sshd_config.akc openssh-5.6p1/sshd_config +--- openssh-5.6p1/sshd_config.akc 2010-08-23 12:15:41.000000000 +0200 ++++ openssh-5.6p1/sshd_config 2010-08-23 12:15:42.000000000 +0200 +@@ -45,6 +45,8 @@ SyslogFacility AUTHPRIV + #RSAAuthentication yes + #PubkeyAuthentication yes + #AuthorizedKeysFile .ssh/authorized_keys ++#AuthorizedKeysCommand none ++#AuthorizedKeysCommandRunAs nobody + + # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts + #RhostsRSAAuthentication no diff --git a/openssh-5.6p1-exit-deadlock.patch b/openssh-5.6p1-exit-deadlock.patch new file mode 100644 index 0000000..278dfa1 --- /dev/null +++ b/openssh-5.6p1-exit-deadlock.patch @@ -0,0 +1,14 @@ +diff -up openssh-5.6p1/channels.c.exit-deadlock openssh-5.6p1/channels.c +--- openssh-5.6p1/channels.c.exit-deadlock 2010-08-05 15:09:48.000000000 +0200 ++++ openssh-5.6p1/channels.c 2010-08-23 12:41:43.000000000 +0200 +@@ -1647,6 +1647,10 @@ channel_handle_wfd(Channel *c, fd_set *r + u_int dlen, olen = 0; + int len; + ++ if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { ++ debug("channel %d: forcing write", c->self); ++ FD_SET(c->wfd, writeset); ++ } + /* Send buffered output data to the socket. */ + if (c->wfd != -1 && + FD_ISSET(c->wfd, writeset) && diff --git a/openssh-5.6p1-fips.patch b/openssh-5.6p1-fips.patch new file mode 100644 index 0000000..7277c3b --- /dev/null +++ b/openssh-5.6p1-fips.patch @@ -0,0 +1,686 @@ +diff -up openssh-5.6p1/auth2-pubkey.c.fips openssh-5.6p1/auth2-pubkey.c +--- openssh-5.6p1/auth2-pubkey.c.fips 2010-08-23 12:43:40.000000000 +0200 ++++ openssh-5.6p1/auth2-pubkey.c 2010-08-23 12:43:41.000000000 +0200 +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include "xmalloc.h" + #include "ssh.h" +@@ -359,7 +360,7 @@ user_search_key_in_file(FILE *f, char *f + found_key = 1; + debug("matching key found: file %s, line %lu", + file, linenum); +- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(found, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); + verbose("Found matching %s key: %s", + key_type(found), fp); + xfree(fp); +diff -up openssh-5.6p1/authfile.c.fips openssh-5.6p1/authfile.c +--- openssh-5.6p1/authfile.c.fips 2010-08-05 05:05:16.000000000 +0200 ++++ openssh-5.6p1/authfile.c 2010-08-23 12:43:41.000000000 +0200 +@@ -146,8 +146,14 @@ key_save_private_rsa1(Key *key, const ch + /* Allocate space for the private part of the key in the buffer. */ + cp = buffer_append_space(&encrypted, buffer_len(&buffer)); + +- cipher_set_key_string(&ciphercontext, cipher, passphrase, +- CIPHER_ENCRYPT); ++ if (cipher_set_key_string(&ciphercontext, cipher, passphrase, ++ CIPHER_ENCRYPT) < 0) { ++ error("cipher_set_key_string failed."); ++ buffer_free(&encrypted); ++ buffer_free(&buffer); ++ return 0; ++ } ++ + cipher_crypt(&ciphercontext, cp, + buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_cleanup(&ciphercontext); +@@ -421,8 +427,14 @@ key_load_private_rsa1(int fd, const char + cp = buffer_append_space(&decrypted, buffer_len(&buffer)); + + /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ +- cipher_set_key_string(&ciphercontext, cipher, passphrase, +- CIPHER_DECRYPT); ++ if (cipher_set_key_string(&ciphercontext, cipher, passphrase, ++ CIPHER_DECRYPT) < 0) { ++ error("cipher_set_key_string failed."); ++ buffer_free(&decrypted); ++ buffer_free(&buffer); ++ goto fail; ++ } ++ + cipher_crypt(&ciphercontext, cp, + buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_cleanup(&ciphercontext); +diff -up openssh-5.6p1/cipher.c.fips openssh-5.6p1/cipher.c +--- openssh-5.6p1/cipher.c.fips 2010-08-23 09:49:50.000000000 +0200 ++++ openssh-5.6p1/cipher.c 2010-08-23 12:43:41.000000000 +0200 +@@ -40,6 +40,7 @@ + #include + + #include ++#include + + #include + #include +@@ -93,6 +94,22 @@ struct Cipher { + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } + }; + ++struct Cipher fips_ciphers[] = { ++ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null }, ++ { "3des", SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des }, ++ ++ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc }, ++ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc }, ++ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc }, ++ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, ++ { "rijndael-cbc@lysator.liu.se", ++ SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, ++ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr }, ++ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr }, ++ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr }, ++ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } ++}; ++ + /*--*/ + + u_int +@@ -135,7 +152,7 @@ Cipher * + cipher_by_name(const char *name) + { + Cipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (strcmp(c->name, name) == 0) + return c; + return NULL; +@@ -145,7 +162,7 @@ Cipher * + cipher_by_number(int id) + { + Cipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (c->number == id) + return c; + return NULL; +@@ -189,7 +206,7 @@ cipher_number(const char *name) + Cipher *c; + if (name == NULL) + return -1; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (strcasecmp(c->name, name) == 0) + return c->number; + return -1; +@@ -296,14 +313,15 @@ cipher_cleanup(CipherContext *cc) + * passphrase and using the resulting 16 bytes as the key. + */ + +-void ++int + cipher_set_key_string(CipherContext *cc, Cipher *cipher, + const char *passphrase, int do_encrypt) + { + MD5_CTX md; + u_char digest[16]; + +- MD5_Init(&md); ++ if (MD5_Init(&md) <= 0) ++ return -1; + MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); + MD5_Final(digest, &md); + +@@ -311,6 +329,7 @@ cipher_set_key_string(CipherContext *cc, + + memset(digest, 0, sizeof(digest)); + memset(&md, 0, sizeof(md)); ++ return 0; + } + + /* +diff -up openssh-5.6p1/cipher-ctr.c.fips openssh-5.6p1/cipher-ctr.c +--- openssh-5.6p1/cipher-ctr.c.fips 2007-06-14 15:21:33.000000000 +0200 ++++ openssh-5.6p1/cipher-ctr.c 2010-08-23 12:43:41.000000000 +0200 +@@ -140,7 +140,8 @@ evp_aes_128_ctr(void) + aes_ctr.do_cipher = ssh_aes_ctr; + #ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | +- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; ++ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV | ++ EVP_CIPH_FLAG_FIPS; + #endif + return (&aes_ctr); + } +diff -up openssh-5.6p1/cipher.h.fips openssh-5.6p1/cipher.h +--- openssh-5.6p1/cipher.h.fips 2009-01-28 06:38:41.000000000 +0100 ++++ openssh-5.6p1/cipher.h 2010-08-23 12:43:41.000000000 +0200 +@@ -78,7 +78,7 @@ void cipher_init(CipherContext *, Ciphe + const u_char *, u_int, int); + void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); + void cipher_cleanup(CipherContext *); +-void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); ++int cipher_set_key_string(CipherContext *, Cipher *, const char *, int); + u_int cipher_blocksize(const Cipher *); + u_int cipher_keylen(const Cipher *); + u_int cipher_is_cbc(const Cipher *); +diff -up openssh-5.6p1/mac.c.fips openssh-5.6p1/mac.c +--- openssh-5.6p1/mac.c.fips 2008-06-13 02:58:50.000000000 +0200 ++++ openssh-5.6p1/mac.c 2010-08-23 12:43:41.000000000 +0200 +@@ -28,6 +28,7 @@ + #include + + #include ++#include + + #include + #include +@@ -47,14 +48,14 @@ + #define SSH_EVP 1 /* OpenSSL EVP-based MAC */ + #define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ + +-struct { ++struct Macs { + char *name; + int type; + const EVP_MD * (*mdfunc)(void); + int truncatebits; /* truncate digest if != 0 */ + int key_len; /* just for UMAC */ + int len; /* just for UMAC */ +-} macs[] = { ++} all_macs[] = { + { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, + { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, -1, -1 }, + { "hmac-md5", SSH_EVP, EVP_md5, 0, -1, -1 }, +@@ -65,9 +66,15 @@ struct { + { NULL, 0, NULL, 0, -1, -1 } + }; + ++struct Macs fips_macs[] = { ++ { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, ++ { NULL, 0, NULL, 0, -1, -1 } ++}; ++ + static void + mac_setup_by_id(Mac *mac, int which) + { ++ struct Macs *macs = FIPS_mode() ? fips_macs : all_macs; + int evp_len; + mac->type = macs[which].type; + if (mac->type == SSH_EVP) { +@@ -88,6 +95,7 @@ int + mac_setup(Mac *mac, char *name) + { + int i; ++ struct Macs *macs = FIPS_mode() ? fips_macs : all_macs; + + for (i = 0; macs[i].name; i++) { + if (strcmp(name, macs[i].name) == 0) { +diff -up openssh-5.6p1/Makefile.in.fips openssh-5.6p1/Makefile.in +--- openssh-5.6p1/Makefile.in.fips 2010-08-23 12:43:40.000000000 +0200 ++++ openssh-5.6p1/Makefile.in 2010-08-23 12:46:24.000000000 +0200 +@@ -141,25 +141,25 @@ libssh.a: $(LIBSSH_OBJS) + $(RANLIB) $@ + + ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) +- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) +- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) ++ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) + + scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o + $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + + ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o +- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o +- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o +- $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o +- $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o + $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +@@ -168,7 +168,7 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) l + $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o +- $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +diff -up openssh-5.6p1/myproposal.h.fips openssh-5.6p1/myproposal.h +--- openssh-5.6p1/myproposal.h.fips 2010-04-16 07:56:22.000000000 +0200 ++++ openssh-5.6p1/myproposal.h 2010-08-23 12:43:41.000000000 +0200 +@@ -58,7 +58,12 @@ + "hmac-sha1-96,hmac-md5-96" + #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" + #define KEX_DEFAULT_LANG "" +- ++#define KEX_FIPS_ENCRYPT \ ++ "aes128-ctr,aes192-ctr,aes256-ctr," \ ++ "aes128-cbc,3des-cbc," \ ++ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" ++#define KEX_FIPS_MAC \ ++ "hmac-sha1" + + static char *myproposal[PROPOSAL_MAX] = { + KEX_DEFAULT_KEX, +diff -up openssh-5.6p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.6p1/openbsd-compat/bsd-arc4random.c +--- openssh-5.6p1/openbsd-compat/bsd-arc4random.c.fips 2010-03-25 22:52:02.000000000 +0100 ++++ openssh-5.6p1/openbsd-compat/bsd-arc4random.c 2010-08-23 12:43:41.000000000 +0200 +@@ -39,6 +39,7 @@ + static int rc4_ready = 0; + static RC4_KEY rc4; + ++#if 0 + unsigned int + arc4random(void) + { +@@ -82,6 +83,32 @@ arc4random_stir(void) + + rc4_ready = REKEY_BYTES; + } ++#else ++unsigned int ++arc4random(void) ++{ ++ unsigned int r = 0; ++ void *rp = &r; ++ ++ if (!rc4_ready) { ++ arc4random_stir(); ++ } ++ RAND_bytes(rp, sizeof(r)); ++ ++ return(r); ++} ++ ++void ++arc4random_stir(void) ++{ ++ unsigned char rand_buf[SEED_SIZE]; ++ ++ if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) ++ fatal("Couldn't obtain random bytes (error %ld)", ++ ERR_get_error()); ++ rc4_ready = 1; ++} ++#endif + #endif /* !HAVE_ARC4RANDOM */ + + #ifndef HAVE_ARC4RANDOM_BUF +diff -up openssh-5.6p1/ssh-add.c.fips openssh-5.6p1/ssh-add.c +--- openssh-5.6p1/ssh-add.c.fips 2010-05-21 06:56:47.000000000 +0200 ++++ openssh-5.6p1/ssh-add.c 2010-08-23 12:43:41.000000000 +0200 +@@ -42,6 +42,7 @@ + #include + + #include ++#include + #include "openbsd-compat/openssl-compat.h" + + #include +@@ -277,7 +278,7 @@ list_identities(AuthenticationConnection + key = ssh_get_next_identity(ac, &comment, version)) { + had_identities = 1; + if (do_fp) { +- fp = key_fingerprint(key, SSH_FP_MD5, ++ fp = key_fingerprint(key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, + SSH_FP_HEX); + printf("%d %s %s (%s)\n", + key_size(key), fp, comment, key_type(key)); +diff -up openssh-5.6p1/ssh-agent.c.fips openssh-5.6p1/ssh-agent.c +--- openssh-5.6p1/ssh-agent.c.fips 2010-04-16 07:56:22.000000000 +0200 ++++ openssh-5.6p1/ssh-agent.c 2010-08-23 12:43:41.000000000 +0200 +@@ -51,6 +51,7 @@ + + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + + #include +@@ -199,9 +200,9 @@ confirm_key(Identity *id) + char *p; + int ret = -1; + +- p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); +- if (ask_permission("Allow use of key %s?\nKey fingerprint %s.", +- id->comment, p)) ++ p = key_fingerprint(id->key, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); ++ if (ask_permission("Allow use of key %s?\nKey %sfingerprint %s.", ++ id->comment, FIPS_mode() ? "SHA1 " : "", p)) + ret = 0; + xfree(p); + +diff -up openssh-5.6p1/ssh.c.fips openssh-5.6p1/ssh.c +--- openssh-5.6p1/ssh.c.fips 2010-08-16 17:59:31.000000000 +0200 ++++ openssh-5.6p1/ssh.c 2010-08-23 12:43:41.000000000 +0200 +@@ -72,6 +72,8 @@ + + #include + #include ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + #include "openbsd-compat/sys-queue.h" + +@@ -235,6 +237,10 @@ main(int ac, char **av) + sanitise_stdfd(); + + __progname = ssh_get_progname(av[0]); ++ SSLeay_add_all_algorithms(); ++ if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) { ++ fatal("FIPS integrity verification test failed."); ++ } + init_rng(); + + /* +@@ -301,6 +307,9 @@ main(int ac, char **av) + "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { + switch (opt) { + case '1': ++ if (FIPS_mode()) { ++ fatal("Protocol 1 not allowed in the FIPS mode."); ++ } + options.protocol = SSH_PROTO_1; + break; + case '2': +@@ -599,7 +608,6 @@ main(int ac, char **av) + if (!host) + usage(); + +- SSLeay_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Initialize the command to execute on remote host. */ +@@ -685,6 +693,10 @@ main(int ac, char **av) + + seed_rng(); + ++ if (FIPS_mode()) { ++ logit("FIPS mode initialized"); ++ } ++ + if (options.user == NULL) + options.user = xstrdup(pw->pw_name); + +@@ -752,6 +764,12 @@ main(int ac, char **av) + + timeout_ms = options.connection_timeout * 1000; + ++ if (FIPS_mode()) { ++ options.protocol &= SSH_PROTO_2; ++ if (options.protocol == 0) ++ fatal("Protocol 2 disabled by configuration but required in the FIPS mode."); ++ } ++ + /* Open a connection to the remote host. */ + if (ssh_connect(host, &hostaddr, options.port, + options.address_family, options.connection_attempts, &timeout_ms, +diff -up openssh-5.6p1/sshconnect2.c.fips openssh-5.6p1/sshconnect2.c +--- openssh-5.6p1/sshconnect2.c.fips 2010-08-23 12:43:41.000000000 +0200 ++++ openssh-5.6p1/sshconnect2.c 2010-08-23 12:43:41.000000000 +0200 +@@ -44,6 +44,8 @@ + #include + #endif + ++#include ++ + #include "openbsd-compat/sys-queue.h" + + #include "xmalloc.h" +@@ -116,6 +118,10 @@ ssh_kex2(char *host, struct sockaddr *ho + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; ++ } else if (FIPS_mode()) { ++ myproposal[PROPOSAL_ENC_ALGS_CTOS] = ++ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; ++ + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); +@@ -131,7 +137,11 @@ ssh_kex2(char *host, struct sockaddr *ho + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; ++ } else if (FIPS_mode()) { ++ myproposal[PROPOSAL_MAC_ALGS_CTOS] = ++ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; + } ++ + if (options.hostkeyalgorithms != NULL) + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + options.hostkeyalgorithms; +@@ -529,8 +539,8 @@ input_userauth_pk_ok(int type, u_int32_t + key->type, pktype); + goto done; + } +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); +- debug2("input_userauth_pk_ok: fp %s", fp); ++ fp = key_fingerprint(key, SSH_FP_SHA1, SSH_FP_HEX); ++ debug2("input_userauth_pk_ok: SHA1 fp %s", fp); + xfree(fp); + + /* +diff -up openssh-5.6p1/sshconnect.c.fips openssh-5.6p1/sshconnect.c +--- openssh-5.6p1/sshconnect.c.fips 2010-04-18 00:08:21.000000000 +0200 ++++ openssh-5.6p1/sshconnect.c 2010-08-23 12:43:41.000000000 +0200 +@@ -40,6 +40,8 @@ + #include + #include + ++#include ++ + #include "xmalloc.h" + #include "key.h" + #include "hostfile.h" +@@ -789,6 +791,7 @@ check_host_key(char *hostname, struct so + goto fail; + } else if (options.strict_host_key_checking == 2) { + char msg1[1024], msg2[1024]; ++ int fips_on = FIPS_mode(); + + if (show_other_keys(host, host_key)) + snprintf(msg1, sizeof(msg1), +@@ -797,8 +800,8 @@ check_host_key(char *hostname, struct so + else + snprintf(msg1, sizeof(msg1), "."); + /* The default */ +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(host_key, SSH_FP_MD5, ++ fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); ++ ra = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, + SSH_FP_RANDOMART); + msg2[0] = '\0'; + if (options.verify_host_key_dns) { +@@ -814,10 +817,10 @@ check_host_key(char *hostname, struct so + snprintf(msg, sizeof(msg), + "The authenticity of host '%.200s (%s)' can't be " + "established%s\n" +- "%s key fingerprint is %s.%s%s\n%s" ++ "%s key %sfingerprint is %s.%s%s\n%s" + "Are you sure you want to continue connecting " + "(yes/no)? ", +- host, ip, msg1, type, fp, ++ host, ip, msg1, type, fips_on ? "SHA1 " : "", fp, + options.visual_host_key ? "\n" : "", + options.visual_host_key ? ra : "", + msg2); +@@ -1151,17 +1154,18 @@ show_key_from_file(const char *file, con + Key *found; + char *fp, *ra; + int line, ret; ++ int fips_on = FIPS_mode(); + + found = key_new(keytype); + if ((ret = lookup_key_in_hostfile_by_type(file, host, + keytype, found, &line))) { +- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART); ++ fp = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); ++ ra = key_fingerprint(found, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_RANDOMART); + logit("WARNING: %s key found for host %s\n" + "in %s:%d\n" +- "%s key fingerprint %s.\n%s\n", ++ "%s key %sfingerprint %s.\n%s\n", + key_type(found), host, file, line, +- key_type(found), fp, ra); ++ key_type(found), fips_on ? "SHA1 ":"", fp, ra); + xfree(ra); + xfree(fp); + } +@@ -1207,8 +1211,9 @@ warn_changed_key(Key *host_key) + { + char *fp; + const char *type = key_type(host_key); ++ int fips_on = FIPS_mode(); + +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(host_key, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); + + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); +@@ -1216,8 +1221,8 @@ warn_changed_key(Key *host_key) + error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + error("It is also possible that the %s host key has just been changed.", type); +- error("The fingerprint for the %s key sent by the remote host is\n%s.", +- type, fp); ++ error("The %sfingerprint for the %s key sent by the remote host is\n%s.", ++ fips_on ? "SHA1 ":"", type, fp); + error("Please contact your system administrator."); + + xfree(fp); +diff -up openssh-5.6p1/sshd.c.fips openssh-5.6p1/sshd.c +--- openssh-5.6p1/sshd.c.fips 2010-08-23 12:43:40.000000000 +0200 ++++ openssh-5.6p1/sshd.c 2010-08-23 12:43:41.000000000 +0200 +@@ -76,6 +76,8 @@ + #include + #include + #include ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + + #ifdef HAVE_SECUREWARE +@@ -1307,6 +1309,12 @@ main(int ac, char **av) + (void)set_auth_parameters(ac, av); + #endif + __progname = ssh_get_progname(av[0]); ++ ++ SSLeay_add_all_algorithms(); ++ if (FIPS_mode() && !FIPSCHECK_verify(NULL, NULL)) { ++ fatal("FIPS integrity verification test failed."); ++ } ++ + init_rng(); + + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ +@@ -1468,8 +1476,6 @@ main(int ac, char **av) + else + closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); + +- SSLeay_add_all_algorithms(); +- + /* + * Force logging to stderr until we have loaded the private host + * key (unless started from inetd) +@@ -1587,6 +1593,10 @@ main(int ac, char **av) + debug("private host key: #%d type %d %s", i, key->type, + key_type(key)); + } ++ if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) { ++ logit("Disabling protocol version 1. Not allowed in the FIPS mode."); ++ options.protocol &= ~SSH_PROTO_1; ++ } + if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { + logit("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; +@@ -1751,6 +1761,10 @@ main(int ac, char **av) + /* Initialize the random number generator. */ + arc4random_stir(); + ++ if (FIPS_mode()) { ++ logit("FIPS mode initialized"); ++ } ++ + /* Chdir to the root directory so that the current disk can be + unmounted if desired. */ + chdir("/"); +@@ -2284,6 +2298,9 @@ do_ssh2_kex(void) + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; ++ } else if (FIPS_mode()) { ++ myproposal[PROPOSAL_ENC_ALGS_CTOS] = ++ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); +@@ -2293,6 +2310,9 @@ do_ssh2_kex(void) + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; ++ } else if (FIPS_mode()) { ++ myproposal[PROPOSAL_MAC_ALGS_CTOS] = ++ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; + } + if (options.compression == COMP_NONE) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = +diff -up openssh-5.6p1/ssh-keygen.c.fips openssh-5.6p1/ssh-keygen.c +--- openssh-5.6p1/ssh-keygen.c.fips 2010-08-23 12:43:40.000000000 +0200 ++++ openssh-5.6p1/ssh-keygen.c 2010-08-23 12:43:41.000000000 +0200 +@@ -21,6 +21,7 @@ + + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + + #include +@@ -692,7 +693,7 @@ do_fingerprint(struct passwd *pw) + enum fp_type fptype; + struct stat st; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; ++ fptype = print_bubblebabble ? SSH_FP_SHA1 : FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5; + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + + if (!have_identity) +@@ -2209,14 +2210,15 @@ passphrase_again: + fclose(f); + + if (!quiet) { +- char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); +- char *ra = key_fingerprint(public, SSH_FP_MD5, ++ int fips_on = FIPS_mode(); ++ char *fp = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); ++ char *ra = key_fingerprint(public, fips_on ? SSH_FP_SHA1 : SSH_FP_MD5, + SSH_FP_RANDOMART); + printf("Your public key has been saved in %s.\n", + identity_file); +- printf("The key fingerprint is:\n"); ++ printf("The key %sfingerprint is:\n", fips_on ? "SHA1 " : ""); + printf("%s %s\n", fp, comment); +- printf("The key's randomart image is:\n"); ++ printf("The key's %srandomart image is:\n", fips_on ? "SHA1 " :""); + printf("%s\n", ra); + xfree(ra); + xfree(fp); diff --git a/openssh-5.6p1-gsskex.patch b/openssh-5.6p1-gsskex.patch new file mode 100644 index 0000000..95da913 --- /dev/null +++ b/openssh-5.6p1-gsskex.patch @@ -0,0 +1,2933 @@ +diff -up openssh-5.6p1/auth2.c.gsskex openssh-5.6p1/auth2.c +--- openssh-5.6p1/auth2.c.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/auth2.c 2010-08-23 12:51:58.000000000 +0200 +@@ -69,6 +69,7 @@ extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif + #ifdef JPAKE +@@ -79,6 +80,7 @@ Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + #ifdef JPAKE +@@ -289,6 +291,7 @@ input_userauth_request(int type, u_int32 + #endif + + authctxt->postponed = 0; ++ authctxt->server_caused_failure = 0; + + /* try to authenticate user */ + m = authmethod_lookup(method); +@@ -361,7 +364,8 @@ userauth_finish(Authctxt *authctxt, int + } else { + + /* Allow initial try of "none" auth without failure penalty */ +- if (authctxt->attempt > 1 || strcmp(method, "none") != 0) ++ if (!authctxt->server_caused_failure && ++ (authctxt->attempt > 1 || strcmp(method, "none") != 0)) + authctxt->failures++; + if (authctxt->failures >= options.max_authtries) { + #ifdef SSH_AUDIT_EVENTS +diff -up openssh-5.6p1/auth2-gss.c.gsskex openssh-5.6p1/auth2-gss.c +--- openssh-5.6p1/auth2-gss.c.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/auth2-gss.c 2010-08-23 12:51:58.000000000 +0200 +@@ -1,7 +1,7 @@ + /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u + static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); + static void input_gssapi_errtok(int, u_int32_t, void *); + ++/* ++ * The 'gssapi_keyex' userauth mechanism. ++ */ ++static int ++userauth_gsskeyex(Authctxt *authctxt) ++{ ++ int authenticated = 0; ++ Buffer b; ++ gss_buffer_desc mic, gssbuf; ++ u_int len; ++ ++ mic.value = packet_get_string(&len); ++ mic.length = len; ++ ++ packet_check_eom(); ++ ++ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, ++ "gssapi-keyex"); ++ ++ gssbuf.value = buffer_ptr(&b); ++ gssbuf.length = buffer_len(&b); ++ ++ /* gss_kex_context is NULL with privsep, so we can't check it here */ ++ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf, &mic)))) ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw)); ++ ++ buffer_free(&b); ++ xfree(mic.value); ++ ++ return (authenticated); ++} ++ + /* + * We only support those mechanisms that we know about (ie ones that we know + * how to check local user kuserok and the like) +@@ -102,6 +136,7 @@ userauth_gssapi(Authctxt *authctxt) + + if (!present) { + xfree(doid); ++ authctxt->server_caused_failure = 1; + return (0); + } + +@@ -109,6 +144,7 @@ userauth_gssapi(Authctxt *authctxt) + if (ctxt != NULL) + ssh_gssapi_delete_ctx(&ctxt); + xfree(doid); ++ authctxt->server_caused_failure = 1; + return (0); + } + +@@ -242,7 +278,8 @@ input_gssapi_exchange_complete(int type, + + packet_check_eom(); + +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw)); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -284,7 +321,8 @@ input_gssapi_mic(int type, u_int32_t ple + gssbuf.length = buffer_len(&b); + + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); + else + logit("GSSAPI MIC check failed"); + +@@ -301,6 +339,12 @@ input_gssapi_mic(int type, u_int32_t ple + userauth_finish(authctxt, authenticated, "gssapi-with-mic"); + } + ++Authmethod method_gsskeyex = { ++ "gssapi-keyex", ++ userauth_gsskeyex, ++ &options.gss_authentication ++}; ++ + Authmethod method_gssapi = { + "gssapi-with-mic", + userauth_gssapi, +diff -up openssh-5.6p1/auth.h.gsskex openssh-5.6p1/auth.h +--- openssh-5.6p1/auth.h.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/auth.h 2010-08-23 12:51:58.000000000 +0200 +@@ -53,6 +53,7 @@ struct Authctxt { + int valid; /* user exists and is allowed to login */ + int attempt; + int failures; ++ int server_caused_failure; + int force_pwchange; + char *user; /* username sent by the client */ + char *service; +diff -up openssh-5.6p1/auth-krb5.c.gsskex openssh-5.6p1/auth-krb5.c +--- openssh-5.6p1/auth-krb5.c.gsskex 2009-12-21 00:49:22.000000000 +0100 ++++ openssh-5.6p1/auth-krb5.c 2010-08-23 12:51:58.000000000 +0200 +@@ -170,8 +170,13 @@ auth_krb5_password(Authctxt *authctxt, c + + len = strlen(authctxt->krb5_ticket_file) + 6; + authctxt->krb5_ccname = xmalloc(len); ++#ifdef USE_CCAPI ++ snprintf(authctxt->krb5_ccname, len, "API:%s", ++ authctxt->krb5_ticket_file); ++#else + snprintf(authctxt->krb5_ccname, len, "FILE:%s", + authctxt->krb5_ticket_file); ++#endif + + #ifdef USE_PAM + if (options.use_pam) +@@ -226,15 +231,22 @@ krb5_cleanup_proc(Authctxt *authctxt) + #ifndef HEIMDAL + krb5_error_code + ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { +- int tmpfd, ret; ++ int ret; + char ccname[40]; + mode_t old_umask; ++#ifdef USE_CCAPI ++ char cctemplate[] = "API:krb5cc_%d"; ++#else ++ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; ++ int tmpfd; ++#endif + + ret = snprintf(ccname, sizeof(ccname), +- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); ++ cctemplate, geteuid()); + if (ret < 0 || (size_t)ret >= sizeof(ccname)) + return ENOMEM; + ++#ifndef USE_CCAPI + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); + umask(old_umask); +@@ -249,6 +261,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c + return errno; + } + close(tmpfd); ++#endif + + return (krb5_cc_resolve(ctx, ccname, ccache)); + } +diff -up openssh-5.6p1/ChangeLog.gssapi.gsskex openssh-5.6p1/ChangeLog.gssapi +--- openssh-5.6p1/ChangeLog.gssapi.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/ChangeLog.gssapi 2010-08-23 12:51:58.000000000 +0200 +@@ -0,0 +1,95 @@ ++20090615 ++ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c ++ sshd.c ] ++ Fix issues identified by Greg Hudson following a code review ++ Check return value of gss_indicate_mechs ++ Protect GSSAPI calls in monitor, so they can only be used if enabled ++ Check return values of bignum functions in key exchange ++ Use BN_clear_free to clear other side's DH value ++ Make ssh_gssapi_id_kex more robust ++ Only configure kex table pointers if GSSAPI is enabled ++ Don't leak mechanism list, or gss mechanism list ++ Cast data.length before printing ++ If serverkey isn't provided, use an empty string, rather than NULL ++ ++20090201 ++ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h ++ ssh_config.5 sshconnet2.c ] ++ Add support for the GSSAPIClientIdentity option, which allows the user ++ to specify which GSSAPI identity to use to contact a given server ++ ++20080404 ++ - [ gss-serv.c ] ++ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow ++ been omitted from a previous version of this patch. Reported by Borislav ++ Stoichkov ++ ++20070317 ++ - [ gss-serv-krb5.c ] ++ Remove C99ism, where new_ccname was being declared in the middle of a ++ function ++ ++20061220 ++ - [ servconf.c ] ++ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and ++ documented, behaviour. Reported by Dan Watson. ++ ++20060910 ++ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c ++ ssh-gss.h ] ++ add support for gss-group14-sha1 key exchange mechanisms ++ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] ++ Add GSSAPIStrictAcceptorCheck option to allow the disabling of ++ acceptor principal checking on multi-homed machines. ++ ++ - [ sshd_config ssh_config ] ++ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample ++ configuration files ++ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] ++ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() ++ Limit length of error messages displayed by client ++ ++20060909 ++ - [ gss-genr.c gss-serv.c ] ++ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server ++ only, where they belong ++ ++ ++20060829 ++ - [ gss-serv-krb5.c ] ++ Fix CCAPI credentials cache name when creating KRB5CCNAME environment ++ variable ++ ++20060828 ++ - [ gss-genr.c ] ++ Avoid Heimdal context freeing problem ++ ++ ++20060818 ++ - [ gss-genr.c ssh-gss.h sshconnect2.c ] ++ Make sure that SPENGO is disabled ++ ++ ++20060421 ++ - [ gssgenr.c, sshconnect2.c ] ++ a few type changes (signed versus unsigned, int versus size_t) to ++ fix compiler errors/warnings ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ kexgssc.c, sshconnect2.c ] ++ fix uninitialized variable warnings ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ gssgenr.c ] ++ pass oid to gss_display_status (helpful when using GSSAPI mechglue) ++ (from jbasney AT ncsa.uiuc.edu) ++ ++ - [ gss-serv-krb5.c ] ++ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H ++ (from jbasney AT ncsa.uiuc.edu) ++ ++ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c ++ add client-side GssapiKeyExchange option ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ sshconnect2.c ] ++ add support for GssapiTrustDns option for gssapi-with-mic ++ (from jbasney AT ncsa.uiuc.edu) ++ +diff -up openssh-5.6p1/clientloop.c.gsskex openssh-5.6p1/clientloop.c +--- openssh-5.6p1/clientloop.c.gsskex 2010-08-03 08:04:46.000000000 +0200 ++++ openssh-5.6p1/clientloop.c 2010-08-23 12:51:58.000000000 +0200 +@@ -111,6 +111,10 @@ + #include "msg.h" + #include "roaming.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* import options */ + extern Options options; + +@@ -1483,6 +1487,13 @@ client_loop(int have_pty, int escape_cha + /* Do channel operations unless rekeying in progress. */ + if (!rekeying) { + channel_after_select(readset, writeset); ++ ++ if (options.gss_renewal_rekey && ++ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) { ++ debug("credentials updated - forcing rekey"); ++ need_rekeying = 1; ++ } ++ + if (need_rekeying || packet_need_rekeying()) { + debug("need rekeying"); + xxx_kex->done = 0; +diff -up openssh-5.6p1/configure.ac.gsskex openssh-5.6p1/configure.ac +--- openssh-5.6p1/configure.ac.gsskex 2010-08-23 12:51:57.000000000 +0200 ++++ openssh-5.6p1/configure.ac 2010-08-23 12:51:58.000000000 +0200 +@@ -477,6 +477,30 @@ main() { if (NSVersionOfRunTimeLibrary(" + [Use tunnel device compatibility to OpenBSD]) + AC_DEFINE(SSH_TUN_PREPEND_AF, 1, + [Prepend the address family to IP tunnel traffic]) ++ AC_MSG_CHECKING(if we have the Security Authorization Session API) ++ AC_TRY_COMPILE([#include ], ++ [SessionCreate(0, 0);], ++ [ac_cv_use_security_session_api="yes" ++ AC_DEFINE(USE_SECURITY_SESSION_API, 1, ++ [platform has the Security Authorization Session API]) ++ LIBS="$LIBS -framework Security" ++ AC_MSG_RESULT(yes)], ++ [ac_cv_use_security_session_api="no" ++ AC_MSG_RESULT(no)]) ++ AC_MSG_CHECKING(if we have an in-memory credentials cache) ++ AC_TRY_COMPILE( ++ [#include ], ++ [cc_context_t c; ++ (void) cc_initialize (&c, 0, NULL, NULL);], ++ [AC_DEFINE(USE_CCAPI, 1, ++ [platform uses an in-memory credentials cache]) ++ LIBS="$LIBS -framework Security" ++ AC_MSG_RESULT(yes) ++ if test "x$ac_cv_use_security_session_api" = "xno"; then ++ AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) ++ fi], ++ [AC_MSG_RESULT(no)] ++ ) + m4_pattern_allow(AU_IPv) + AC_CHECK_DECL(AU_IPv4, [], + AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) +diff -up openssh-5.6p1/gss-genr.c.gsskex openssh-5.6p1/gss-genr.c +--- openssh-5.6p1/gss-genr.c.gsskex 2009-06-22 08:11:07.000000000 +0200 ++++ openssh-5.6p1/gss-genr.c 2010-08-23 12:51:58.000000000 +0200 +@@ -39,12 +39,167 @@ + #include "buffer.h" + #include "log.h" + #include "ssh2.h" ++#include "cipher.h" ++#include "key.h" ++#include "kex.h" ++#include + + #include "ssh-gss.h" + + extern u_char *session_id2; + extern u_int session_id2_len; + ++typedef struct { ++ char *encoded; ++ gss_OID oid; ++} ssh_gss_kex_mapping; ++ ++/* ++ * XXX - It would be nice to find a more elegant way of handling the ++ * XXX passing of the key exchange context to the userauth routines ++ */ ++ ++Gssctxt *gss_kex_context = NULL; ++ ++static ssh_gss_kex_mapping *gss_enc2oid = NULL; ++ ++int ++ssh_gssapi_oid_table_ok() { ++ return (gss_enc2oid != NULL); ++} ++ ++/* ++ * Return a list of the gss-group1-sha1 mechanisms supported by this program ++ * ++ * We test mechanisms to ensure that we can use them, to avoid starting ++ * a key exchange with a bad mechanism ++ */ ++ ++char * ++ssh_gssapi_client_mechanisms(const char *host, const char *client) { ++ gss_OID_set gss_supported; ++ OM_uint32 min_status; ++ ++ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) ++ return NULL; ++ ++ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, ++ host, client)); ++} ++ ++char * ++ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, ++ const char *host, const char *client) { ++ Buffer buf; ++ size_t i; ++ int oidpos, enclen; ++ char *mechs, *encoded; ++ u_char digest[EVP_MAX_MD_SIZE]; ++ char deroid[2]; ++ const EVP_MD *evp_md = EVP_md5(); ++ EVP_MD_CTX md; ++ ++ if (gss_enc2oid != NULL) { ++ for (i = 0; gss_enc2oid[i].encoded != NULL; i++) ++ xfree(gss_enc2oid[i].encoded); ++ xfree(gss_enc2oid); ++ } ++ ++ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * ++ (gss_supported->count + 1)); ++ ++ buffer_init(&buf); ++ ++ oidpos = 0; ++ for (i = 0; i < gss_supported->count; i++) { ++ if (gss_supported->elements[i].length < 128 && ++ (*check)(NULL, &(gss_supported->elements[i]), host, client)) { ++ ++ deroid[0] = SSH_GSS_OIDTYPE; ++ deroid[1] = gss_supported->elements[i].length; ++ ++ EVP_DigestInit(&md, evp_md); ++ EVP_DigestUpdate(&md, deroid, 2); ++ EVP_DigestUpdate(&md, ++ gss_supported->elements[i].elements, ++ gss_supported->elements[i].length); ++ EVP_DigestFinal(&md, digest, NULL); ++ ++ encoded = xmalloc(EVP_MD_size(evp_md) * 2); ++ enclen = __b64_ntop(digest, EVP_MD_size(evp_md), ++ encoded, EVP_MD_size(evp_md) * 2); ++ ++ if (oidpos != 0) ++ buffer_put_char(&buf, ','); ++ ++ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, ++ sizeof(KEX_GSS_GEX_SHA1_ID) - 1); ++ buffer_append(&buf, encoded, enclen); ++ buffer_put_char(&buf, ','); ++ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, ++ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); ++ buffer_append(&buf, encoded, enclen); ++ buffer_put_char(&buf, ','); ++ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, ++ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); ++ buffer_append(&buf, encoded, enclen); ++ ++ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); ++ gss_enc2oid[oidpos].encoded = encoded; ++ oidpos++; ++ } ++ } ++ gss_enc2oid[oidpos].oid = NULL; ++ gss_enc2oid[oidpos].encoded = NULL; ++ ++ buffer_put_char(&buf, '\0'); ++ ++ mechs = xmalloc(buffer_len(&buf)); ++ buffer_get(&buf, mechs, buffer_len(&buf)); ++ buffer_free(&buf); ++ ++ if (strlen(mechs) == 0) { ++ xfree(mechs); ++ mechs = NULL; ++ } ++ ++ return (mechs); ++} ++ ++gss_OID ++ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { ++ int i = 0; ++ ++ switch (kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) ++ return GSS_C_NO_OID; ++ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; ++ break; ++ case KEX_GSS_GRP14_SHA1: ++ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) ++ return GSS_C_NO_OID; ++ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; ++ break; ++ case KEX_GSS_GEX_SHA1: ++ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) ++ return GSS_C_NO_OID; ++ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; ++ break; ++ default: ++ return GSS_C_NO_OID; ++ } ++ ++ while (gss_enc2oid[i].encoded != NULL && ++ strcmp(name, gss_enc2oid[i].encoded) != 0) ++ i++; ++ ++ if (gss_enc2oid[i].oid != NULL && ctx != NULL) ++ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); ++ ++ return gss_enc2oid[i].oid; ++} ++ + /* Check that the OID in a data stream matches that in the context */ + int + ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) +@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de + } + + ctx->major = gss_init_sec_context(&ctx->minor, +- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, ++ ctx->client_creds, &ctx->context, ctx->name, ctx->oid, + GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, + 0, NULL, recv_tok, NULL, send_tok, flags, NULL); + +@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con + } + + OM_uint32 ++ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) ++{ ++ gss_buffer_desc gssbuf; ++ gss_name_t gssname; ++ OM_uint32 status; ++ gss_OID_set oidset; ++ ++ gssbuf.value = (void *) name; ++ gssbuf.length = strlen(gssbuf.value); ++ ++ gss_create_empty_oid_set(&status, &oidset); ++ gss_add_oid_set_member(&status, ctx->oid, &oidset); ++ ++ ctx->major = gss_import_name(&ctx->minor, &gssbuf, ++ GSS_C_NT_USER_NAME, &gssname); ++ ++ if (!ctx->major) ++ ctx->major = gss_acquire_cred(&ctx->minor, ++ gssname, 0, oidset, GSS_C_INITIATE, ++ &ctx->client_creds, NULL, NULL); ++ ++ gss_release_name(&status, &gssname); ++ gss_release_oid_set(&status, &oidset); ++ ++ if (ctx->major) ++ ssh_gssapi_error(ctx); ++ ++ return(ctx->major); ++} ++ ++OM_uint32 + ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) + { ++ if (ctx == NULL) ++ return -1; ++ + if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, + GSS_C_QOP_DEFAULT, buffer, hash))) + ssh_gssapi_error(ctx); +@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer + return (ctx->major); + } + ++/* Priviledged when used by server */ ++OM_uint32 ++ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) ++{ ++ if (ctx == NULL) ++ return -1; ++ ++ ctx->major = gss_verify_mic(&ctx->minor, ctx->context, ++ gssbuf, gssmic, NULL); ++ ++ return (ctx->major); ++} ++ + void + ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, + const char *context) +@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha + } + + int +-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) ++ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, ++ const char *client) + { + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + OM_uint32 major, minor; + gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; ++ Gssctxt *intctx = NULL; ++ ++ if (ctx == NULL) ++ ctx = &intctx; + + /* RFC 4462 says we MUST NOT do SPNEGO */ + if (oid->length == spnego_oid.length && +@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx, oid); + major = ssh_gssapi_import_name(*ctx, host); ++ ++ if (!GSS_ERROR(major) && client) ++ major = ssh_gssapi_client_identity(*ctx, client); ++ + if (!GSS_ERROR(major)) { + major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, + NULL); +@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + GSS_C_NO_BUFFER); + } + +- if (GSS_ERROR(major)) ++ if (GSS_ERROR(major) || intctx != NULL) + ssh_gssapi_delete_ctx(ctx); + + return (!GSS_ERROR(major)); + } + ++int ++ssh_gssapi_credentials_updated(Gssctxt *ctxt) { ++ static gss_name_t saved_name = GSS_C_NO_NAME; ++ static OM_uint32 saved_lifetime = 0; ++ static gss_OID saved_mech = GSS_C_NO_OID; ++ static gss_name_t name; ++ static OM_uint32 last_call = 0; ++ OM_uint32 lifetime, now, major, minor; ++ int equal; ++ gss_cred_usage_t usage = GSS_C_INITIATE; ++ ++ now = time(NULL); ++ ++ if (ctxt) { ++ debug("Rekey has happened - updating saved versions"); ++ ++ if (saved_name != GSS_C_NO_NAME) ++ gss_release_name(&minor, &saved_name); ++ ++ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, ++ &saved_name, &saved_lifetime, NULL, NULL); ++ ++ if (!GSS_ERROR(major)) { ++ saved_mech = ctxt->oid; ++ saved_lifetime+= now; ++ } else { ++ /* Handle the error */ ++ } ++ return 0; ++ } ++ ++ if (now - last_call < 10) ++ return 0; ++ ++ last_call = now; ++ ++ if (saved_mech == GSS_C_NO_OID) ++ return 0; ++ ++ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, ++ &name, &lifetime, NULL, NULL); ++ if (major == GSS_S_CREDENTIALS_EXPIRED) ++ return 0; ++ else if (GSS_ERROR(major)) ++ return 0; ++ ++ major = gss_compare_name(&minor, saved_name, name, &equal); ++ gss_release_name(&minor, &name); ++ if (GSS_ERROR(major)) ++ return 0; ++ ++ if (equal && (saved_lifetime < lifetime + now - 10)) ++ return 1; ++ ++ return 0; ++} ++ + #endif /* GSSAPI */ +diff -up openssh-5.6p1/gss-serv.c.gsskex openssh-5.6p1/gss-serv.c +--- openssh-5.6p1/gss-serv.c.gsskex 2008-05-19 07:05:07.000000000 +0200 ++++ openssh-5.6p1/gss-serv.c 2010-08-23 12:51:58.000000000 +0200 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -45,15 +45,20 @@ + #include "channels.h" + #include "session.h" + #include "misc.h" ++#include "servconf.h" ++#include "uidswap.h" + + #include "ssh-gss.h" ++#include "monitor_wrap.h" ++ ++extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, +- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; ++ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; + + ssh_gssapi_mech gssapi_null_mech = +- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; ++ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; + + #ifdef KRB5 + extern ssh_gssapi_mech gssapi_kerberos_mech; +@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) + char lname[MAXHOSTNAMELEN]; + gss_OID_set oidset; + +- gss_create_empty_oid_set(&status, &oidset); +- gss_add_oid_set_member(&status, ctx->oid, &oidset); ++ if (options.gss_strict_acceptor) { ++ gss_create_empty_oid_set(&status, &oidset); ++ gss_add_oid_set_member(&status, ctx->oid, &oidset); ++ ++ if (gethostname(lname, MAXHOSTNAMELEN)) { ++ gss_release_oid_set(&status, &oidset); ++ return (-1); ++ } + +- if (gethostname(lname, MAXHOSTNAMELEN)) { +- gss_release_oid_set(&status, &oidset); +- return (-1); +- } ++ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { ++ gss_release_oid_set(&status, &oidset); ++ return (ctx->major); ++ } ++ ++ if ((ctx->major = gss_acquire_cred(&ctx->minor, ++ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, ++ NULL, NULL))) ++ ssh_gssapi_error(ctx); + +- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { + gss_release_oid_set(&status, &oidset); + return (ctx->major); ++ } else { ++ ctx->name = GSS_C_NO_NAME; ++ ctx->creds = GSS_C_NO_CREDENTIAL; + } +- +- if ((ctx->major = gss_acquire_cred(&ctx->minor, +- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) +- ssh_gssapi_error(ctx); +- +- gss_release_oid_set(&status, &oidset); +- return (ctx->major); ++ return GSS_S_COMPLETE; + } + + /* Privileged */ +@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss + } + + /* Unprivileged */ ++char * ++ssh_gssapi_server_mechanisms() { ++ gss_OID_set supported; ++ ++ ssh_gssapi_supported_oids(&supported); ++ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, ++ NULL, NULL)); ++} ++ ++/* Unprivileged */ ++int ++ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, ++ const char *dummy) { ++ Gssctxt *ctx = NULL; ++ int res; ++ ++ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); ++ ssh_gssapi_delete_ctx(&ctx); ++ ++ return (res); ++} ++ ++/* Unprivileged */ + void + ssh_gssapi_supported_oids(gss_OID_set *oidset) + { +@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o + gss_OID_set supported; + + gss_create_empty_oid_set(&min_status, oidset); +- gss_indicate_mechs(&min_status, &supported); ++ ++ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) ++ return; + + while (supported_mechs[i]->name != NULL) { + if (GSS_ERROR(gss_test_oid_set_member(&min_status, +@@ -247,8 +284,48 @@ OM_uint32 + ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + { + int i = 0; ++ int equal = 0; ++ gss_name_t new_name = GSS_C_NO_NAME; ++ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; ++ ++ if (options.gss_store_rekey && client->used && ctx->client_creds) { ++ if (client->mech->oid.length != ctx->oid->length || ++ (memcmp(client->mech->oid.elements, ++ ctx->oid->elements, ctx->oid->length) !=0)) { ++ debug("Rekeyed credentials have different mechanism"); ++ return GSS_S_COMPLETE; ++ } ++ ++ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &new_name, ++ NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ ctx->major = gss_compare_name(&ctx->minor, client->name, ++ new_name, &equal); + +- gss_buffer_desc ename; ++ if (GSS_ERROR(ctx->major)) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ if (!equal) { ++ debug("Rekeyed credentials have different name"); ++ return GSS_S_COMPLETE; ++ } ++ ++ debug("Marking rekeyed credentials for export"); ++ ++ gss_release_name(&ctx->minor, &client->name); ++ gss_release_cred(&ctx->minor, &client->creds); ++ client->name = new_name; ++ client->creds = ctx->client_creds; ++ ctx->client_creds = GSS_C_NO_CREDENTIAL; ++ client->updated = 1; ++ return GSS_S_COMPLETE; ++ } + + client->mech = NULL; + +@@ -263,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + if (client->mech == NULL) + return GSS_S_FAILURE; + ++ if (ctx->client_creds && ++ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, + &client->displayname, NULL))) { + ssh_gssapi_error(ctx); +@@ -280,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + return (ctx->major); + } + ++ gss_release_buffer(&ctx->minor, &ename); ++ + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; +@@ -327,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int + + /* Privileged */ + int +-ssh_gssapi_userok(char *user) ++ssh_gssapi_userok(char *user, struct passwd *pw) + { + OM_uint32 lmin; + +@@ -337,9 +423,11 @@ ssh_gssapi_userok(char *user) + return 0; + } + if (gssapi_client.mech && gssapi_client.mech->userok) +- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) ++ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { ++ gssapi_client.used = 1; ++ gssapi_client.store.owner = pw; + return 1; +- else { ++ } else { + /* Destroy delegated credentials if userok fails */ + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); +@@ -352,14 +440,90 @@ ssh_gssapi_userok(char *user) + return (0); + } + +-/* Privileged */ +-OM_uint32 +-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) ++/* These bits are only used for rekeying. The unpriviledged child is running ++ * as the user, the monitor is root. ++ * ++ * In the child, we want to : ++ * *) Ask the monitor to store our credentials into the store we specify ++ * *) If it succeeds, maybe do a PAM update ++ */ ++ ++/* Stuff for PAM */ ++ ++#ifdef USE_PAM ++static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, ++ struct pam_response **resp, void *data) + { +- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, +- gssbuf, gssmic, NULL); ++ return (PAM_CONV_ERR); ++} ++#endif + +- return (ctx->major); ++void ++ssh_gssapi_rekey_creds() { ++ int ok; ++ int ret; ++#ifdef USE_PAM ++ pam_handle_t *pamh = NULL; ++ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; ++ char *envstr; ++#endif ++ ++ if (gssapi_client.store.filename == NULL && ++ gssapi_client.store.envval == NULL && ++ gssapi_client.store.envvar == NULL) ++ return; ++ ++ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); ++ ++ if (!ok) ++ return; ++ ++ debug("Rekeyed credentials stored successfully"); ++ ++ /* Actually managing to play with the ssh pam stack from here will ++ * be next to impossible. In any case, we may want different options ++ * for rekeying. So, use our own :) ++ */ ++#ifdef USE_PAM ++ if (!use_privsep) { ++ debug("Not even going to try and do PAM with privsep disabled"); ++ return; ++ } ++ ++ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, ++ &pamconv, &pamh); ++ if (ret) ++ return; ++ ++ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, ++ gssapi_client.store.envval); ++ ++ ret = pam_putenv(pamh, envstr); ++ if (!ret) ++ pam_setcred(pamh, PAM_REINITIALIZE_CRED); ++ pam_end(pamh, PAM_SUCCESS); ++#endif ++} ++ ++int ++ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { ++ int ok = 0; ++ ++ /* Check we've got credentials to store */ ++ if (!gssapi_client.updated) ++ return 0; ++ ++ gssapi_client.updated = 0; ++ ++ temporarily_use_uid(gssapi_client.store.owner); ++ if (gssapi_client.mech && gssapi_client.mech->updatecreds) ++ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); ++ else ++ debug("No update function for this mechanism"); ++ ++ restore_uid(); ++ ++ return ok; + } + + #endif +diff -up openssh-5.6p1/gss-serv-krb5.c.gsskex openssh-5.6p1/gss-serv-krb5.c +--- openssh-5.6p1/gss-serv-krb5.c.gsskex 2006-09-01 07:38:36.000000000 +0200 ++++ openssh-5.6p1/gss-serv-krb5.c 2010-08-23 12:51:58.000000000 +0200 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + krb5_principal princ; + OM_uint32 maj_status, min_status; + int len; ++ const char *new_ccname; + + if (client->creds == NULL) { + debug("No credentials stored"); +@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + return; + } + +- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); ++ new_ccname = krb5_cc_get_name(krb_context, ccache); ++ + client->store.envvar = "KRB5CCNAME"; +- len = strlen(client->store.filename) + 6; +- client->store.envval = xmalloc(len); +- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); ++#ifdef USE_CCAPI ++ xasprintf(&client->store.envval, "API:%s", new_ccname); ++ client->store.filename = NULL; ++#else ++ xasprintf(&client->store.envval, "FILE:%s", new_ccname); ++ client->store.filename = xstrdup(new_ccname); ++#endif + + #ifdef USE_PAM + if (options.use_pam) +@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + return; + } + ++int ++ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, ++ ssh_gssapi_client *client) ++{ ++ krb5_ccache ccache = NULL; ++ krb5_principal principal = NULL; ++ char *name = NULL; ++ krb5_error_code problem; ++ OM_uint32 maj_status, min_status; ++ ++ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { ++ logit("krb5_cc_resolve(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ return 0; ++ } ++ ++ /* Find out who the principal in this cache is */ ++ if ((problem = krb5_cc_get_principal(krb_context, ccache, ++ &principal))) { ++ logit("krb5_cc_get_principal(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { ++ logit("krb5_unparse_name(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ ++ if (strcmp(name,client->exportedname.value)!=0) { ++ debug("Name in local credentials cache differs. Not storing"); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ krb5_free_unparsed_name(krb_context, name); ++ return 0; ++ } ++ krb5_free_unparsed_name(krb_context, name); ++ ++ /* Name matches, so lets get on with it! */ ++ ++ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { ++ logit("krb5_cc_initialize(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ krb5_free_principal(krb_context, principal); ++ ++ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, ++ ccache))) { ++ logit("gss_krb5_copy_ccache() failed. Sorry!"); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ return 1; ++} ++ + ssh_gssapi_mech gssapi_kerberos_mech = { + "toWM5Slw5Ew8Mqkay+al2g==", + "Kerberos", +@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { + NULL, + &ssh_gssapi_krb5_userok, + NULL, +- &ssh_gssapi_krb5_storecreds ++ &ssh_gssapi_krb5_storecreds, ++ &ssh_gssapi_krb5_updatecreds + }; + + #endif /* KRB5 */ +diff -up openssh-5.6p1/kex.c.gsskex openssh-5.6p1/kex.c +--- openssh-5.6p1/kex.c.gsskex 2010-01-08 06:50:41.000000000 +0100 ++++ openssh-5.6p1/kex.c 2010-08-23 12:51:58.000000000 +0200 +@@ -50,6 +50,10 @@ + #include "monitor.h" + #include "roaming.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= 0x00907000L + # if defined(HAVE_EVP_SHA256) + # define evp_ssh_sha256 EVP_sha256 +@@ -326,6 +330,20 @@ choose_kex(Kex *k, char *client, char *s + k->kex_type = KEX_DH_GEX_SHA256; + k->evp_md = evp_ssh_sha256(); + #endif ++#ifdef GSSAPI ++ } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, ++ sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { ++ k->kex_type = KEX_GSS_GEX_SHA1; ++ k->evp_md = EVP_sha1(); ++ } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, ++ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { ++ k->kex_type = KEX_GSS_GRP1_SHA1; ++ k->evp_md = EVP_sha1(); ++ } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, ++ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { ++ k->kex_type = KEX_GSS_GRP14_SHA1; ++ k->evp_md = EVP_sha1(); ++#endif + } else + fatal("bad kex alg %s", k->name); + } +diff -up openssh-5.6p1/kexgssc.c.gsskex openssh-5.6p1/kexgssc.c +--- openssh-5.6p1/kexgssc.c.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/kexgssc.c 2010-08-23 12:51:58.000000000 +0200 +@@ -0,0 +1,334 @@ ++/* ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "includes.h" ++ ++#ifdef GSSAPI ++ ++#include "includes.h" ++ ++#include ++#include ++ ++#include ++ ++#include "xmalloc.h" ++#include "buffer.h" ++#include "ssh2.h" ++#include "key.h" ++#include "cipher.h" ++#include "kex.h" ++#include "log.h" ++#include "packet.h" ++#include "dh.h" ++ ++#include "ssh-gss.h" ++ ++void ++kexgss_client(Kex *kex) { ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; ++ Gssctxt *ctxt; ++ OM_uint32 maj_status, min_status, ret_flags; ++ u_int klen, kout, slen = 0, hashlen, strlen; ++ DH *dh; ++ BIGNUM *dh_server_pub = NULL; ++ BIGNUM *shared_secret = NULL; ++ BIGNUM *p = NULL; ++ BIGNUM *g = NULL; ++ u_char *kbuf, *hash; ++ u_char *serverhostkey = NULL; ++ u_char *empty = ""; ++ char *msg; ++ char *lang; ++ int type = 0; ++ int first = 1; ++ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; ++ ++ /* Initialise our GSSAPI world */ ++ ssh_gssapi_build_ctx(&ctxt); ++ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) ++ == GSS_C_NO_OID) ++ fatal("Couldn't identify host exchange"); ++ ++ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(ctxt, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ dh = dh_new_group1(); ++ break; ++ case KEX_GSS_GRP14_SHA1: ++ dh = dh_new_group14(); ++ break; ++ case KEX_GSS_GEX_SHA1: ++ debug("Doing group exchange\n"); ++ nbits = dh_estimate(kex->we_need * 8); ++ packet_start(SSH2_MSG_KEXGSS_GROUPREQ); ++ packet_put_int(min); ++ packet_put_int(nbits); ++ packet_put_int(max); ++ ++ packet_send(); ++ ++ packet_read_expect(SSH2_MSG_KEXGSS_GROUP); ++ ++ if ((p = BN_new()) == NULL) ++ fatal("BN_new() failed"); ++ packet_get_bignum2(p); ++ if ((g = BN_new()) == NULL) ++ fatal("BN_new() failed"); ++ packet_get_bignum2(g); ++ packet_check_eom(); ++ ++ if (BN_num_bits(p) < min || BN_num_bits(p) > max) ++ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", ++ min, BN_num_bits(p), max); ++ ++ dh = dh_new_group(g, p); ++ break; ++ default: ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); ++ } ++ ++ /* Step 1 - e is dh->pub_key */ ++ dh_gen_key(dh, kex->we_need * 8); ++ ++ /* This is f, we initialise it now to make life easier */ ++ dh_server_pub = BN_new(); ++ if (dh_server_pub == NULL) ++ fatal("dh_server_pub == NULL"); ++ ++ token_ptr = GSS_C_NO_BUFFER; ++ ++ do { ++ debug("Calling gss_init_sec_context"); ++ ++ maj_status = ssh_gssapi_init_ctx(ctxt, ++ kex->gss_deleg_creds, token_ptr, &send_tok, ++ &ret_flags); ++ ++ if (GSS_ERROR(maj_status)) { ++ if (send_tok.length != 0) { ++ packet_start(SSH2_MSG_KEXGSS_CONTINUE); ++ packet_put_string(send_tok.value, ++ send_tok.length); ++ } ++ fatal("gss_init_context failed"); ++ } ++ ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ xfree(recv_tok.value); ++ ++ if (maj_status == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); ++ ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (first) { ++ packet_start(SSH2_MSG_KEXGSS_INIT); ++ packet_put_string(send_tok.value, ++ send_tok.length); ++ packet_put_bignum2(dh->pub_key); ++ first = 0; ++ } else { ++ packet_start(SSH2_MSG_KEXGSS_CONTINUE); ++ packet_put_string(send_tok.value, ++ send_tok.length); ++ } ++ packet_send(); ++ gss_release_buffer(&min_status, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ do { ++ type = packet_read(); ++ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { ++ debug("Received KEXGSS_HOSTKEY"); ++ if (serverhostkey) ++ fatal("Server host key received more than once"); ++ serverhostkey = ++ packet_get_string(&slen); ++ } ++ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); ++ ++ switch (type) { ++ case SSH2_MSG_KEXGSS_CONTINUE: ++ debug("Received GSSAPI_CONTINUE"); ++ if (maj_status == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ recv_tok.value = packet_get_string(&strlen); ++ recv_tok.length = strlen; ++ break; ++ case SSH2_MSG_KEXGSS_COMPLETE: ++ debug("Received GSSAPI_COMPLETE"); ++ packet_get_bignum2(dh_server_pub); ++ msg_tok.value = packet_get_string(&strlen); ++ msg_tok.length = strlen; ++ ++ /* Is there a token included? */ ++ if (packet_get_char()) { ++ recv_tok.value= ++ packet_get_string(&strlen); ++ recv_tok.length = strlen; ++ /* If we're already complete - protocol error */ ++ if (maj_status == GSS_S_COMPLETE) ++ packet_disconnect("Protocol error: received token when complete"); ++ } else { ++ /* No token included */ ++ if (maj_status != GSS_S_COMPLETE) ++ packet_disconnect("Protocol error: did not receive final token"); ++ } ++ break; ++ case SSH2_MSG_KEXGSS_ERROR: ++ debug("Received Error"); ++ maj_status = packet_get_int(); ++ min_status = packet_get_int(); ++ msg = packet_get_string(NULL); ++ lang = packet_get_string(NULL); ++ fatal("GSSAPI Error: \n%.400s",msg); ++ default: ++ packet_disconnect("Protocol error: didn't expect packet type %d", ++ type); ++ } ++ token_ptr = &recv_tok; ++ } else { ++ /* No data, and not complete */ ++ if (maj_status != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ } ++ } while (maj_status & GSS_S_CONTINUE_NEEDED); ++ ++ /* ++ * We _must_ have received a COMPLETE message in reply from the ++ * server, which will have set dh_server_pub and msg_tok ++ */ ++ ++ if (type != SSH2_MSG_KEXGSS_COMPLETE) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ ++ /* Check f in range [1, p-1] */ ++ if (!dh_pub_is_valid(dh, dh_server_pub)) ++ packet_disconnect("bad server public DH value"); ++ ++ /* compute K=f^x mod p */ ++ klen = DH_size(dh); ++ kbuf = xmalloc(klen); ++ kout = DH_compute_key(kbuf, dh_server_pub, dh); ++ if (kout < 0) ++ fatal("DH_compute_key: failed"); ++ ++ shared_secret = BN_new(); ++ if (shared_secret == NULL) ++ fatal("kexgss_client: BN_new failed"); ++ ++ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) ++ fatal("kexdh_client: BN_bin2bn failed"); ++ ++ memset(kbuf, 0, klen); ++ xfree(kbuf); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ kex_dh_hash( kex->client_version_string, ++ kex->server_version_string, ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ (serverhostkey ? serverhostkey : empty), slen, ++ dh->pub_key, /* e */ ++ dh_server_pub, /* f */ ++ shared_secret, /* K */ ++ &hash, &hashlen ++ ); ++ break; ++ case KEX_GSS_GEX_SHA1: ++ kexgex_hash( ++ kex->evp_md, ++ kex->client_version_string, ++ kex->server_version_string, ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ (serverhostkey ? serverhostkey : empty), slen, ++ min, nbits, max, ++ dh->p, dh->g, ++ dh->pub_key, ++ dh_server_pub, ++ shared_secret, ++ &hash, &hashlen ++ ); ++ break; ++ default: ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); ++ } ++ ++ gssbuf.value = hash; ++ gssbuf.length = hashlen; ++ ++ /* Verify that the hash matches the MIC we just got. */ ++ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) ++ packet_disconnect("Hash's MIC didn't verify"); ++ ++ xfree(msg_tok.value); ++ ++ DH_free(dh); ++ if (serverhostkey) ++ xfree(serverhostkey); ++ BN_clear_free(dh_server_pub); ++ ++ /* save session id */ ++ if (kex->session_id == NULL) { ++ kex->session_id_len = hashlen; ++ kex->session_id = xmalloc(kex->session_id_len); ++ memcpy(kex->session_id, hash, kex->session_id_len); ++ } ++ ++ if (kex->gss_deleg_creds) ++ ssh_gssapi_credentials_updated(ctxt); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = ctxt; ++ else ++ ssh_gssapi_delete_ctx(&ctxt); ++ ++ kex_derive_keys(kex, hash, hashlen, shared_secret); ++ BN_clear_free(shared_secret); ++ kex_finish(kex); ++} ++ ++#endif /* GSSAPI */ +diff -up openssh-5.6p1/kexgsss.c.gsskex openssh-5.6p1/kexgsss.c +--- openssh-5.6p1/kexgsss.c.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/kexgsss.c 2010-08-23 12:51:58.000000000 +0200 +@@ -0,0 +1,288 @@ ++/* ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "includes.h" ++ ++#ifdef GSSAPI ++ ++#include ++ ++#include ++#include ++ ++#include "xmalloc.h" ++#include "buffer.h" ++#include "ssh2.h" ++#include "key.h" ++#include "cipher.h" ++#include "kex.h" ++#include "log.h" ++#include "packet.h" ++#include "dh.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "servconf.h" ++ ++extern ServerOptions options; ++ ++void ++kexgss_server(Kex *kex) ++{ ++ OM_uint32 maj_status, min_status; ++ ++ /* ++ * Some GSSAPI implementations use the input value of ret_flags (an ++ * output variable) as a means of triggering mechanism specific ++ * features. Initializing it to zero avoids inadvertently ++ * activating this non-standard behaviour. ++ */ ++ ++ OM_uint32 ret_flags = 0; ++ gss_buffer_desc gssbuf, recv_tok, msg_tok; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ Gssctxt *ctxt = NULL; ++ u_int slen, klen, kout, hashlen; ++ u_char *kbuf, *hash; ++ DH *dh; ++ int min = -1, max = -1, nbits = -1; ++ BIGNUM *shared_secret = NULL; ++ BIGNUM *dh_client_pub = NULL; ++ int type = 0; ++ gss_OID oid; ++ char *mechs; ++ ++ /* Initialise GSSAPI */ ++ ++ /* If we're rekeying, privsep means that some of the private structures ++ * in the GSSAPI code are no longer available. This kludges them back ++ * into life ++ */ ++ if (!ssh_gssapi_oid_table_ok()) ++ if ((mechs = ssh_gssapi_server_mechanisms())) ++ xfree(mechs); ++ ++ debug2("%s: Identifying %s", __func__, kex->name); ++ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); ++ if (oid == GSS_C_NO_OID) ++ fatal("Unknown gssapi mechanism"); ++ ++ debug2("%s: Acquiring credentials", __func__); ++ ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ fatal("Unable to acquire credentials for the server"); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ dh = dh_new_group1(); ++ break; ++ case KEX_GSS_GRP14_SHA1: ++ dh = dh_new_group14(); ++ break; ++ case KEX_GSS_GEX_SHA1: ++ debug("Doing group exchange"); ++ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); ++ min = packet_get_int(); ++ nbits = packet_get_int(); ++ max = packet_get_int(); ++ min = MAX(DH_GRP_MIN, min); ++ max = MIN(DH_GRP_MAX, max); ++ packet_check_eom(); ++ if (max < min || nbits < min || max < nbits) ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", ++ min, nbits, max); ++ dh = PRIVSEP(choose_dh(min, nbits, max)); ++ if (dh == NULL) ++ packet_disconnect("Protocol error: no matching group found"); ++ ++ packet_start(SSH2_MSG_KEXGSS_GROUP); ++ packet_put_bignum2(dh->p); ++ packet_put_bignum2(dh->g); ++ packet_send(); ++ ++ packet_write_wait(); ++ break; ++ default: ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); ++ } ++ ++ dh_gen_key(dh, kex->we_need * 8); ++ ++ do { ++ debug("Wait SSH2_MSG_GSSAPI_INIT"); ++ type = packet_read(); ++ switch(type) { ++ case SSH2_MSG_KEXGSS_INIT: ++ if (dh_client_pub != NULL) ++ fatal("Received KEXGSS_INIT after initialising"); ++ recv_tok.value = packet_get_string(&slen); ++ recv_tok.length = slen; ++ ++ if ((dh_client_pub = BN_new()) == NULL) ++ fatal("dh_client_pub == NULL"); ++ ++ packet_get_bignum2(dh_client_pub); ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ break; ++ case SSH2_MSG_KEXGSS_CONTINUE: ++ recv_tok.value = packet_get_string(&slen); ++ recv_tok.length = slen; ++ break; ++ default: ++ packet_disconnect( ++ "Protocol error: didn't expect packet type %d", ++ type); ++ } ++ ++ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, ++ &send_tok, &ret_flags)); ++ ++ xfree(recv_tok.value); ++ ++ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) ++ fatal("Zero length token output when incomplete"); ++ ++ if (dh_client_pub == NULL) ++ fatal("No client public key"); ++ ++ if (maj_status & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ packet_start(SSH2_MSG_KEXGSS_CONTINUE); ++ packet_put_string(send_tok.value, send_tok.length); ++ packet_send(); ++ gss_release_buffer(&min_status, &send_tok); ++ } ++ } while (maj_status & GSS_S_CONTINUE_NEEDED); ++ ++ if (GSS_ERROR(maj_status)) { ++ if (send_tok.length > 0) { ++ packet_start(SSH2_MSG_KEXGSS_CONTINUE); ++ packet_put_string(send_tok.value, send_tok.length); ++ packet_send(); ++ } ++ fatal("accept_ctx died"); ++ } ++ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual Authentication flag wasn't set"); ++ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity flag wasn't set"); ++ ++ if (!dh_pub_is_valid(dh, dh_client_pub)) ++ packet_disconnect("bad client public DH value"); ++ ++ klen = DH_size(dh); ++ kbuf = xmalloc(klen); ++ kout = DH_compute_key(kbuf, dh_client_pub, dh); ++ if (kout < 0) ++ fatal("DH_compute_key: failed"); ++ ++ shared_secret = BN_new(); ++ if (shared_secret == NULL) ++ fatal("kexgss_server: BN_new failed"); ++ ++ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) ++ fatal("kexgss_server: BN_bin2bn failed"); ++ ++ memset(kbuf, 0, klen); ++ xfree(kbuf); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ kex_dh_hash( ++ kex->client_version_string, kex->server_version_string, ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ NULL, 0, /* Change this if we start sending host keys */ ++ dh_client_pub, dh->pub_key, shared_secret, ++ &hash, &hashlen ++ ); ++ break; ++ case KEX_GSS_GEX_SHA1: ++ kexgex_hash( ++ kex->evp_md, ++ kex->client_version_string, kex->server_version_string, ++ buffer_ptr(&kex->peer), buffer_len(&kex->peer), ++ buffer_ptr(&kex->my), buffer_len(&kex->my), ++ NULL, 0, ++ min, nbits, max, ++ dh->p, dh->g, ++ dh_client_pub, ++ dh->pub_key, ++ shared_secret, ++ &hash, &hashlen ++ ); ++ break; ++ default: ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); ++ } ++ ++ BN_clear_free(dh_client_pub); ++ ++ if (kex->session_id == NULL) { ++ kex->session_id_len = hashlen; ++ kex->session_id = xmalloc(kex->session_id_len); ++ memcpy(kex->session_id, hash, kex->session_id_len); ++ } ++ ++ gssbuf.value = hash; ++ gssbuf.length = hashlen; ++ ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) ++ fatal("Couldn't get MIC"); ++ ++ packet_start(SSH2_MSG_KEXGSS_COMPLETE); ++ packet_put_bignum2(dh->pub_key); ++ packet_put_string(msg_tok.value,msg_tok.length); ++ ++ if (send_tok.length != 0) { ++ packet_put_char(1); /* true */ ++ packet_put_string(send_tok.value, send_tok.length); ++ } else { ++ packet_put_char(0); /* false */ ++ } ++ packet_send(); ++ ++ gss_release_buffer(&min_status, &send_tok); ++ gss_release_buffer(&min_status, &msg_tok); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = ctxt; ++ else ++ ssh_gssapi_delete_ctx(&ctxt); ++ ++ DH_free(dh); ++ ++ kex_derive_keys(kex, hash, hashlen, shared_secret); ++ BN_clear_free(shared_secret); ++ kex_finish(kex); ++ ++ /* If this was a rekey, then save out any delegated credentials we ++ * just exchanged. */ ++ if (options.gss_store_rekey) ++ ssh_gssapi_rekey_creds(); ++} ++#endif /* GSSAPI */ +diff -up openssh-5.6p1/kex.h.gsskex openssh-5.6p1/kex.h +--- openssh-5.6p1/kex.h.gsskex 2010-02-26 21:55:05.000000000 +0100 ++++ openssh-5.6p1/kex.h 2010-08-23 12:51:58.000000000 +0200 +@@ -67,6 +67,9 @@ enum kex_exchange { + KEX_DH_GRP14_SHA1, + KEX_DH_GEX_SHA1, + KEX_DH_GEX_SHA256, ++ KEX_GSS_GRP1_SHA1, ++ KEX_GSS_GRP14_SHA1, ++ KEX_GSS_GEX_SHA1, + KEX_MAX + }; + +@@ -123,6 +126,12 @@ struct Kex { + sig_atomic_t done; + int flags; + const EVP_MD *evp_md; ++#ifdef GSSAPI ++ int gss_deleg_creds; ++ int gss_trust_dns; ++ char *gss_host; ++ char *gss_client; ++#endif + char *client_version_string; + char *server_version_string; + int (*verify_host_key)(Key *); +@@ -146,6 +155,11 @@ void kexdh_server(Kex *); + void kexgex_client(Kex *); + void kexgex_server(Kex *); + ++#ifdef GSSAPI ++void kexgss_client(Kex *); ++void kexgss_server(Kex *); ++#endif ++ + void + kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); +diff -up openssh-5.6p1/key.c.gsskex openssh-5.6p1/key.c +--- openssh-5.6p1/key.c.gsskex 2010-07-16 05:58:37.000000000 +0200 ++++ openssh-5.6p1/key.c 2010-08-23 12:56:03.000000000 +0200 +@@ -1020,6 +1020,8 @@ key_type_from_name(char *name) + return KEY_RSA_CERT; + } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) { + return KEY_DSA_CERT; ++ } else if (strcmp(name, "null") == 0) { ++ return KEY_NULL; + } + debug2("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +diff -up openssh-5.6p1/key.h.gsskex openssh-5.6p1/key.h +--- openssh-5.6p1/key.h.gsskex 2010-04-16 07:56:22.000000000 +0200 ++++ openssh-5.6p1/key.h 2010-08-23 12:56:32.000000000 +0200 +@@ -39,6 +39,7 @@ enum types { + KEY_DSA_CERT, + KEY_RSA_CERT_V00, + KEY_DSA_CERT_V00, ++ KEY_NULL, + KEY_UNSPEC + }; + enum fp_type { +diff -up openssh-5.6p1/Makefile.in.gsskex openssh-5.6p1/Makefile.in +--- openssh-5.6p1/Makefile.in.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/Makefile.in 2010-08-23 12:51:58.000000000 +0200 +@@ -76,11 +76,11 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b + monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ + kexgex.o kexdhc.o kexgexc.o msg.o progressmeter.o dns.o \ + entropy.o gss-genr.o umac.o jpake.o schnorr.o \ +- ssh-pkcs11.o ++ ssh-pkcs11.o kexgssc.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ +- roaming_common.o roaming_client.o ++ roaming_common.o roaming_client.o kexgssc.o + + SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + sshpty.o sshlogin.o servconf.o serverloop.o \ +@@ -93,7 +93,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + auth2-gss.o gss-serv.o gss-serv-krb5.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ + audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ +- roaming_common.o roaming_serv.o ++ roaming_common.o roaming_serv.o kexgsss.o + + MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out + MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5 +diff -up openssh-5.6p1/monitor.c.gsskex openssh-5.6p1/monitor.c +--- openssh-5.6p1/monitor.c.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/monitor.c 2010-08-23 12:51:58.000000000 +0200 +@@ -175,6 +175,8 @@ int mm_answer_gss_setup_ctx(int, Buffer + int mm_answer_gss_accept_ctx(int, Buffer *); + int mm_answer_gss_userok(int, Buffer *); + int mm_answer_gss_checkmic(int, Buffer *); ++int mm_answer_gss_sign(int, Buffer *); ++int mm_answer_gss_updatecreds(int, Buffer *); + #endif + + #ifdef SSH_AUDIT_EVENTS +@@ -247,6 +249,7 @@ struct mon_table mon_dispatch_proto20[] + {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, + {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, ++ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, + #endif + #ifdef JPAKE + {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, +@@ -259,6 +262,12 @@ struct mon_table mon_dispatch_proto20[] + }; + + struct mon_table mon_dispatch_postauth20[] = { ++#ifdef GSSAPI ++ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, ++ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, ++ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, ++ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, ++#endif + {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, + {MONITOR_REQ_SIGN, 0, mm_answer_sign}, + {MONITOR_REQ_PTY, 0, mm_answer_pty}, +@@ -363,6 +372,10 @@ monitor_child_preauth(Authctxt *_authctx + /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); ++#ifdef GSSAPI ++ /* and for the GSSAPI key exchange */ ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++#endif + } else { + mon_dispatch = mon_dispatch_proto15; + +@@ -449,6 +462,10 @@ monitor_child_postauth(struct monitor *p + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); ++#ifdef GSSAPI ++ /* and for the GSSAPI key exchange */ ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++#endif + } else { + mon_dispatch = mon_dispatch_postauth15; + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); +@@ -1723,6 +1740,13 @@ mm_get_kex(Buffer *m) + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; ++ } ++#endif + kex->server = 1; + kex->hostkey_type = buffer_get_int(m); + kex->kex_type = buffer_get_int(m); +@@ -1929,6 +1953,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer + OM_uint32 major; + u_int len; + ++ if (!options.gss_authentication && !options.gss_keyex) ++ fatal("In GSSAPI monitor when GSSAPI is disabled"); ++ + goid.elements = buffer_get_string(m, &len); + goid.length = len; + +@@ -1956,6 +1983,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe + OM_uint32 flags = 0; /* GSI needs this */ + u_int len; + ++ if (!options.gss_authentication && !options.gss_keyex) ++ fatal("In GSSAPI monitor when GSSAPI is disabled"); ++ + in.value = buffer_get_string(m, &len); + in.length = len; + major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); +@@ -1973,6 +2003,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); + } + return (0); + } +@@ -1984,6 +2015,9 @@ mm_answer_gss_checkmic(int sock, Buffer + OM_uint32 ret; + u_int len; + ++ if (!options.gss_authentication && !options.gss_keyex) ++ fatal("In GSSAPI monitor when GSSAPI is disabled"); ++ + gssbuf.value = buffer_get_string(m, &len); + gssbuf.length = len; + mic.value = buffer_get_string(m, &len); +@@ -2010,7 +2044,11 @@ mm_answer_gss_userok(int sock, Buffer *m + { + int authenticated; + +- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); ++ if (!options.gss_authentication && !options.gss_keyex) ++ fatal("In GSSAPI monitor when GSSAPI is disabled"); ++ ++ authenticated = authctxt->valid && ++ ssh_gssapi_userok(authctxt->user, authctxt->pw); + + buffer_clear(m); + buffer_put_int(m, authenticated); +@@ -2023,6 +2061,74 @@ mm_answer_gss_userok(int sock, Buffer *m + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } ++ ++int ++mm_answer_gss_sign(int socket, Buffer *m) ++{ ++ gss_buffer_desc data; ++ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; ++ OM_uint32 major, minor; ++ u_int len; ++ ++ if (!options.gss_authentication && !options.gss_keyex) ++ fatal("In GSSAPI monitor when GSSAPI is disabled"); ++ ++ data.value = buffer_get_string(m, &len); ++ data.length = len; ++ if (data.length != 20) ++ fatal("%s: data length incorrect: %d", __func__, ++ (int) data.length); ++ ++ /* Save the session ID on the first time around */ ++ if (session_id2_len == 0) { ++ session_id2_len = data.length; ++ session_id2 = xmalloc(session_id2_len); ++ memcpy(session_id2, data.value, session_id2_len); ++ } ++ major = ssh_gssapi_sign(gsscontext, &data, &hash); ++ ++ xfree(data.value); ++ ++ buffer_clear(m); ++ buffer_put_int(m, major); ++ buffer_put_string(m, hash.value, hash.length); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); ++ ++ gss_release_buffer(&minor, &hash); ++ ++ /* Turn on getpwnam permissions */ ++ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); ++ ++ /* And credential updating, for when rekeying */ ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); ++ ++ return (0); ++} ++ ++int ++mm_answer_gss_updatecreds(int socket, Buffer *m) { ++ ssh_gssapi_ccache store; ++ int ok; ++ ++ store.filename = buffer_get_string(m, NULL); ++ store.envvar = buffer_get_string(m, NULL); ++ store.envval = buffer_get_string(m, NULL); ++ ++ ok = ssh_gssapi_update_creds(&store); ++ ++ xfree(store.filename); ++ xfree(store.envvar); ++ xfree(store.envval); ++ ++ buffer_clear(m); ++ buffer_put_int(m, ok); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); ++ ++ return(0); ++} ++ + #endif /* GSSAPI */ + + #ifdef JPAKE +diff -up openssh-5.6p1/monitor.h.gsskex openssh-5.6p1/monitor.h +--- openssh-5.6p1/monitor.h.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/monitor.h 2010-08-23 12:51:58.000000000 +0200 +@@ -56,6 +56,8 @@ enum monitor_reqtype { + MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, + MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, + MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, ++ MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, ++ MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, + MONITOR_REQ_PAM_START, + MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, + MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, +diff -up openssh-5.6p1/monitor_wrap.c.gsskex openssh-5.6p1/monitor_wrap.c +--- openssh-5.6p1/monitor_wrap.c.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/monitor_wrap.c 2010-08-23 12:51:58.000000000 +0200 +@@ -1250,7 +1250,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss + } + + int +-mm_ssh_gssapi_userok(char *user) ++mm_ssh_gssapi_userok(char *user, struct passwd *pw) + { + Buffer m; + int authenticated = 0; +@@ -1267,6 +1267,51 @@ mm_ssh_gssapi_userok(char *user) + debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); + return (authenticated); + } ++ ++OM_uint32 ++mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) ++{ ++ Buffer m; ++ OM_uint32 major; ++ u_int len; ++ ++ buffer_init(&m); ++ buffer_put_string(&m, data->value, data->length); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); ++ ++ major = buffer_get_int(&m); ++ hash->value = buffer_get_string(&m, &len); ++ hash->length = len; ++ ++ buffer_free(&m); ++ ++ return(major); ++} ++ ++int ++mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) ++{ ++ Buffer m; ++ int ok; ++ ++ buffer_init(&m); ++ ++ buffer_put_cstring(&m, store->filename ? store->filename : ""); ++ buffer_put_cstring(&m, store->envvar ? store->envvar : ""); ++ buffer_put_cstring(&m, store->envval ? store->envval : ""); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); ++ ++ ok = buffer_get_int(&m); ++ ++ buffer_free(&m); ++ ++ return (ok); ++} ++ + #endif /* GSSAPI */ + + #ifdef JPAKE +diff -up openssh-5.6p1/monitor_wrap.h.gsskex openssh-5.6p1/monitor_wrap.h +--- openssh-5.6p1/monitor_wrap.h.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/monitor_wrap.h 2010-08-23 12:51:58.000000000 +0200 +@@ -60,8 +60,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K + OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); + OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); +-int mm_ssh_gssapi_userok(char *user); ++int mm_ssh_gssapi_userok(char *user, struct passwd *); + OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); ++OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); ++int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); + #endif + + #ifdef USE_PAM +diff -up openssh-5.6p1/readconf.c.gsskex openssh-5.6p1/readconf.c +--- openssh-5.6p1/readconf.c.gsskex 2010-08-03 08:04:46.000000000 +0200 ++++ openssh-5.6p1/readconf.c 2010-08-23 12:57:26.000000000 +0200 +@@ -127,6 +127,7 @@ typedef enum { + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, ++ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, + oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oSendEnv, oControlPath, oControlMaster, oControlPersist, + oHashKnownHosts, +@@ -166,10 +167,18 @@ static struct { + { "afstokenpassing", oUnsupported }, + #if defined(GSSAPI) + { "gssapiauthentication", oGssAuthentication }, ++ { "gssapikeyexchange", oGssKeyEx }, + { "gssapidelegatecredentials", oGssDelegateCreds }, ++ { "gssapitrustdns", oGssTrustDns }, ++ { "gssapiclientidentity", oGssClientIdentity }, ++ { "gssapirenewalforcesrekey", oGssRenewalRekey }, + #else + { "gssapiauthentication", oUnsupported }, ++ { "gssapikeyexchange", oUnsupported }, + { "gssapidelegatecredentials", oUnsupported }, ++ { "gssapitrustdns", oUnsupported }, ++ { "gssapiclientidentity", oUnsupported }, ++ { "gssapirenewalforcesrekey", oUnsupported }, + #endif + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, +@@ -474,10 +483,26 @@ parse_flag: + intptr = &options->gss_authentication; + goto parse_flag; + ++ case oGssKeyEx: ++ intptr = &options->gss_keyex; ++ goto parse_flag; ++ + case oGssDelegateCreds: + intptr = &options->gss_deleg_creds; + goto parse_flag; + ++ case oGssTrustDns: ++ intptr = &options->gss_trust_dns; ++ goto parse_flag; ++ ++ case oGssClientIdentity: ++ charptr = &options->gss_client_identity; ++ goto parse_string; ++ ++ case oGssRenewalRekey: ++ intptr = &options->gss_renewal_rekey; ++ goto parse_flag; ++ + case oBatchMode: + intptr = &options->batch_mode; + goto parse_flag; +@@ -1058,7 +1083,11 @@ initialize_options(Options * options) + options->pubkey_authentication = -1; + options->challenge_response_authentication = -1; + options->gss_authentication = -1; ++ options->gss_keyex = -1; + options->gss_deleg_creds = -1; ++ options->gss_trust_dns = -1; ++ options->gss_renewal_rekey = -1; ++ options->gss_client_identity = NULL; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->kbd_interactive_devices = NULL; +@@ -1156,8 +1185,14 @@ fill_default_options(Options * options) + options->challenge_response_authentication = 1; + if (options->gss_authentication == -1) + options->gss_authentication = 0; ++ if (options->gss_keyex == -1) ++ options->gss_keyex = 0; + if (options->gss_deleg_creds == -1) + options->gss_deleg_creds = 0; ++ if (options->gss_trust_dns == -1) ++ options->gss_trust_dns = 0; ++ if (options->gss_renewal_rekey == -1) ++ options->gss_renewal_rekey = 0; + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) +diff -up openssh-5.6p1/readconf.h.gsskex openssh-5.6p1/readconf.h +--- openssh-5.6p1/readconf.h.gsskex 2010-08-03 08:04:46.000000000 +0200 ++++ openssh-5.6p1/readconf.h 2010-08-23 12:51:59.000000000 +0200 +@@ -46,7 +46,11 @@ typedef struct { + int challenge_response_authentication; + /* Try S/Key or TIS, authentication. */ + int gss_authentication; /* Try GSS authentication */ ++ int gss_keyex; /* Try GSS key exchange */ + int gss_deleg_creds; /* Delegate GSS credentials */ ++ int gss_trust_dns; /* Trust DNS for GSS canonicalization */ ++ int gss_renewal_rekey; /* Credential renewal forces rekey */ ++ char *gss_client_identity; /* Principal to initiate GSSAPI with */ + int password_authentication; /* Try password + * authentication. */ + int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ +diff -up openssh-5.6p1/servconf.c.gsskex openssh-5.6p1/servconf.c +--- openssh-5.6p1/servconf.c.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/servconf.c 2010-08-23 12:51:59.000000000 +0200 +@@ -93,7 +93,10 @@ initialize_server_options(ServerOptions + options->kerberos_ticket_cleanup = -1; + options->kerberos_get_afs_token = -1; + options->gss_authentication=-1; ++ options->gss_keyex = -1; + options->gss_cleanup_creds = -1; ++ options->gss_strict_acceptor = -1; ++ options->gss_store_rekey = -1; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->challenge_response_authentication = -1; +@@ -218,8 +221,14 @@ fill_default_server_options(ServerOption + options->kerberos_get_afs_token = 0; + if (options->gss_authentication == -1) + options->gss_authentication = 0; ++ if (options->gss_keyex == -1) ++ options->gss_keyex = 0; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; ++ if (options->gss_strict_acceptor == -1) ++ options->gss_strict_acceptor = 1; ++ if (options->gss_store_rekey == -1) ++ options->gss_store_rekey = 0; + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) +@@ -313,7 +322,9 @@ typedef enum { + sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, + sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, +- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, ++ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, ++ sGssKeyEx, sGssStoreRekey, ++ sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sZeroKnowledgePasswordAuthentication, sHostCertificate, +@@ -377,9 +388,15 @@ static struct { + #ifdef GSSAPI + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, + { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, ++ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, ++ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, + { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, +@@ -941,10 +958,22 @@ process_server_config_line(ServerOptions + intptr = &options->gss_authentication; + goto parse_flag; + ++ case sGssKeyEx: ++ intptr = &options->gss_keyex; ++ goto parse_flag; ++ + case sGssCleanupCreds: + intptr = &options->gss_cleanup_creds; + goto parse_flag; + ++ case sGssStrictAcceptor: ++ intptr = &options->gss_strict_acceptor; ++ goto parse_flag; ++ ++ case sGssStoreRekey: ++ intptr = &options->gss_store_rekey; ++ goto parse_flag; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +diff -up openssh-5.6p1/servconf.h.gsskex openssh-5.6p1/servconf.h +--- openssh-5.6p1/servconf.h.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/servconf.h 2010-08-23 12:51:59.000000000 +0200 +@@ -94,7 +94,10 @@ typedef struct { + int kerberos_get_afs_token; /* If true, try to get AFS token if + * authenticated with Kerberos. */ + int gss_authentication; /* If true, permit GSSAPI authentication */ ++ int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ ++ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ ++ int gss_store_rekey; + int password_authentication; /* If true, permit password + * authentication. */ + int kbd_interactive_authentication; /* If true, permit */ +diff -up openssh-5.6p1/ssh_config.5.gsskex openssh-5.6p1/ssh_config.5 +--- openssh-5.6p1/ssh_config.5.gsskex 2010-08-05 05:03:13.000000000 +0200 ++++ openssh-5.6p1/ssh_config.5 2010-08-23 12:51:59.000000000 +0200 +@@ -509,11 +509,38 @@ Specifies whether user authentication ba + The default is + .Dq no . + Note that this option applies to protocol version 2 only. ++.It Cm GSSAPIKeyExchange ++Specifies whether key exchange based on GSSAPI may be used. When using ++GSSAPI key exchange the server need not have a host key. ++The default is ++.Dq no . ++Note that this option applies to protocol version 2 only. ++.It Cm GSSAPIClientIdentity ++If set, specifies the GSSAPI client identity that ssh should use when ++connecting to the server. The default is unset, which means that the default ++identity will be used. + .It Cm GSSAPIDelegateCredentials + Forward (delegate) credentials to the server. + The default is + .Dq no . +-Note that this option applies to protocol version 2 only. ++Note that this option applies to protocol version 2 connections using GSSAPI. ++.It Cm GSSAPIRenewalForcesRekey ++If set to ++.Dq yes ++then renewal of the client's GSSAPI credentials will force the rekeying of the ++ssh connection. With a compatible server, this can delegate the renewed ++credentials to a session on the server. ++The default is ++.Dq no . ++.It Cm GSSAPITrustDns ++Set to ++.Dq yes to indicate that the DNS is trusted to securely canonicalize ++the name of the host being connected to. If ++.Dq no, the hostname entered on the ++command line will be passed untouched to the GSSAPI library. ++The default is ++.Dq no . ++This option only applies to protocol version 2 connections using GSSAPI. + .It Cm HashKnownHosts + Indicates that + .Xr ssh 1 +diff -up openssh-5.6p1/ssh_config.gsskex openssh-5.6p1/ssh_config +--- openssh-5.6p1/ssh_config.gsskex 2010-08-23 12:51:55.000000000 +0200 ++++ openssh-5.6p1/ssh_config 2010-08-23 12:51:59.000000000 +0200 +@@ -26,6 +26,8 @@ + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes + # AddressFamily any +diff -up openssh-5.6p1/sshconnect2.c.gsskex openssh-5.6p1/sshconnect2.c +--- openssh-5.6p1/sshconnect2.c.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/sshconnect2.c 2010-08-23 12:51:59.000000000 +0200 +@@ -108,9 +108,34 @@ ssh_kex2(char *host, struct sockaddr *ho + { + Kex *kex; + ++#ifdef GSSAPI ++ char *orig = NULL, *gss = NULL; ++ char *gss_host = NULL; ++#endif ++ + xxx_host = host; + xxx_hostaddr = hostaddr; + ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ /* Add the GSSAPI mechanisms currently supported on this ++ * client to the key exchange algorithm proposal */ ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ ++ if (options.gss_trust_dns) ++ gss_host = (char *)get_canonical_hostname(1); ++ else ++ gss_host = host; ++ ++ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); ++ if (gss) { ++ debug("Offering GSSAPI proposal: %s", gss); ++ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], ++ "%s,%s", gss, orig); ++ } ++ } ++#endif ++ + if (options.ciphers == (char *)-1) { + logit("No valid ciphers for protocol version 2 given, using defaults."); + options.ciphers = NULL; +@@ -146,6 +171,17 @@ ssh_kex2(char *host, struct sockaddr *ho + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + options.hostkeyalgorithms; + ++#ifdef GSSAPI ++ /* If we've got GSSAPI algorithms, then we also support the ++ * 'null' hostkey, as a last resort */ ++ if (options.gss_keyex && gss) { ++ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; ++ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], ++ "%s,null", orig); ++ xfree(gss); ++ } ++#endif ++ + if (options.rekey_limit) + packet_set_rekey_limit((u_int32_t)options.rekey_limit); + +@@ -155,10 +191,26 @@ ssh_kex2(char *host, struct sockaddr *ho + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; ++ } ++#endif + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->verify_host_key=&verify_host_key_callback; + ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->gss_deleg_creds = options.gss_deleg_creds; ++ kex->gss_trust_dns = options.gss_trust_dns; ++ kex->gss_client = options.gss_client_identity; ++ kex->gss_host = gss_host; ++ } ++#endif ++ + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); +@@ -253,6 +305,7 @@ void input_gssapi_token(int type, u_int3 + void input_gssapi_hash(int type, u_int32_t, void *); + void input_gssapi_error(int, u_int32_t, void *); + void input_gssapi_errtok(int, u_int32_t, void *); ++int userauth_gsskeyex(Authctxt *authctxt); + #endif + + void userauth(Authctxt *, char *); +@@ -268,6 +321,10 @@ static char *authmethods_get(void); + + Authmethod authmethods[] = { + #ifdef GSSAPI ++ {"gssapi-keyex", ++ userauth_gsskeyex, ++ &options.gss_authentication, ++ NULL}, + {"gssapi-with-mic", + userauth_gssapi, + NULL, +@@ -576,23 +633,35 @@ userauth_gssapi(Authctxt *authctxt) + int ok = 0; + char* remotehost = NULL; + const char* canonicalhost = get_canonical_hostname(1); ++ const char *gss_host; ++ + if ( strcmp( canonicalhost, "UNKNOWN" ) == 0 ) + remotehost = authctxt->host; + else + remotehost = canonicalhost; + ++ if (options.gss_trust_dns) ++// gss_host = get_canonical_hostname(1); ++ gss_host = remotehost; ++ else ++ gss_host = authctxt->host; ++ + /* Try one GSSAPI method at a time, rather than sending them all at + * once. */ + + if (gss_supported == NULL) +- gss_indicate_mechs(&min, &gss_supported); ++ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { ++ gss_supported = NULL; ++ return 0; ++ } + + /* Check to see if the mechanism is usable before we offer it */ + while (mech < gss_supported->count && !ok) { + /* My DER encoding requires length<128 */ + if (gss_supported->elements[mech].length < 128 && + ssh_gssapi_check_mechanism(&gssctxt, +- &gss_supported->elements[mech], remotehost)) { ++ &gss_supported->elements[mech], gss_host, ++ options.gss_client_identity)) { + ok = 1; /* Mechanism works */ + } else { + mech++; +@@ -689,8 +758,8 @@ input_gssapi_response(int type, u_int32_ + { + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; +- int oidlen; +- char *oidv; ++ u_int oidlen; ++ u_char *oidv; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); +@@ -800,6 +869,48 @@ input_gssapi_error(int type, u_int32_t p + xfree(msg); + xfree(lang); + } ++ ++int ++userauth_gsskeyex(Authctxt *authctxt) ++{ ++ Buffer b; ++ gss_buffer_desc gssbuf; ++ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ms; ++ ++ static int attempt = 0; ++ if (attempt++ >= 1) ++ return (0); ++ ++ if (gss_kex_context == NULL) { ++ debug("No valid Key exchange context"); ++ return (0); ++ } ++ ++ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, ++ "gssapi-keyex"); ++ ++ gssbuf.value = buffer_ptr(&b); ++ gssbuf.length = buffer_len(&b); ++ ++ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { ++ buffer_free(&b); ++ return (0); ++ } ++ ++ packet_start(SSH2_MSG_USERAUTH_REQUEST); ++ packet_put_cstring(authctxt->server_user); ++ packet_put_cstring(authctxt->service); ++ packet_put_cstring(authctxt->method->name); ++ packet_put_string(mic.value, mic.length); ++ packet_send(); ++ ++ buffer_free(&b); ++ gss_release_buffer(&ms, &mic); ++ ++ return (1); ++} ++ + #endif /* GSSAPI */ + + int +diff -up openssh-5.6p1/sshd.c.gsskex openssh-5.6p1/sshd.c +--- openssh-5.6p1/sshd.c.gsskex 2010-08-23 12:51:58.000000000 +0200 ++++ openssh-5.6p1/sshd.c 2010-08-23 12:51:59.000000000 +0200 +@@ -129,6 +129,10 @@ int allow_severity; + int deny_severity; + #endif /* LIBWRAP */ + ++#ifdef USE_SECURITY_SESSION_API ++#include ++#endif ++ + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif +@@ -1601,10 +1605,13 @@ main(int ac, char **av) + logit("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; + } ++#ifndef GSSAPI ++ /* The GSSAPI key exchange can run without a host key */ + if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { + logit("Disabling protocol version 2. Could not load host key"); + options.protocol &= ~SSH_PROTO_2; + } ++#endif + if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { + logit("sshd: no hostkeys available -- exiting."); + exit(1); +@@ -1937,6 +1944,60 @@ main(int ac, char **av) + /* Log the connection. */ + verbose("Connection from %.500s port %d", remote_ip, remote_port); + ++#ifdef USE_SECURITY_SESSION_API ++ /* ++ * Create a new security session for use by the new user login if ++ * the current session is the root session or we are not launched ++ * by inetd (eg: debugging mode or server mode). We do not ++ * necessarily need to create a session if we are launched from ++ * inetd because Panther xinetd will create a session for us. ++ * ++ * The only case where this logic will fail is if there is an ++ * inetd running in a non-root session which is not creating ++ * new sessions for us. Then all the users will end up in the ++ * same session (bad). ++ * ++ * When the client exits, the session will be destroyed for us ++ * automatically. ++ * ++ * We must create the session before any credentials are stored ++ * (including AFS pags, which happens a few lines below). ++ */ ++ { ++ OSStatus err = 0; ++ SecuritySessionId sid = 0; ++ SessionAttributeBits sattrs = 0; ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("Current Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ ++ if (inetd_flag && !(sattrs & sessionIsRoot)) ++ debug("Running in inetd mode in a non-root session... " ++ "assuming inetd created the session for us."); ++ else { ++ debug("Creating new security session..."); ++ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); ++ if (err) ++ error("SessionCreate() failed with error %.8X", ++ (unsigned) err); ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, ++ &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("New Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ } ++ } ++#endif ++ + /* + * We don't want to listen forever unless the other side + * successfully authenticates itself. So we set up an alarm which is +@@ -2324,12 +2385,61 @@ do_ssh2_kex(void) + + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); + ++#ifdef GSSAPI ++ { ++ char *orig; ++ char *gss = NULL; ++ char *newstr = NULL; ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ ++ /* ++ * If we don't have a host key, then there's no point advertising ++ * the other key exchange algorithms ++ */ ++ ++ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) ++ orig = NULL; ++ ++ if (options.gss_keyex) ++ gss = ssh_gssapi_server_mechanisms(); ++ else ++ gss = NULL; ++ ++ if (gss && orig) ++ xasprintf(&newstr, "%s,%s", gss, orig); ++ else if (gss) ++ newstr = gss; ++ else if (orig) ++ newstr = orig; ++ ++ /* ++ * If we've got GSSAPI mechanisms, then we've got the 'null' host ++ * key alg, but we can't tell people about it unless its the only ++ * host key algorithm we support ++ */ ++ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) ++ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; ++ ++ if (newstr) ++ myproposal[PROPOSAL_KEX_ALGS] = newstr; ++ else ++ fatal("No supported key exchange algorithms"); ++ } ++#endif ++ + /* start key exchange */ + kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; ++ } ++#endif + kex->server = 1; + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; +diff -up openssh-5.6p1/sshd_config.5.gsskex openssh-5.6p1/sshd_config.5 +--- openssh-5.6p1/sshd_config.5.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/sshd_config.5 2010-08-23 12:51:59.000000000 +0200 +@@ -424,12 +424,40 @@ Specifies whether user authentication ba + The default is + .Dq no . + Note that this option applies to protocol version 2 only. ++.It Cm GSSAPIKeyExchange ++Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange ++doesn't rely on ssh keys to verify host identity. ++The default is ++.Dq no . ++Note that this option applies to protocol version 2 only. + .It Cm GSSAPICleanupCredentials + Specifies whether to automatically destroy the user's credentials cache + on logout. + The default is + .Dq yes . + Note that this option applies to protocol version 2 only. ++.It Cm GSSAPIStrictAcceptorCheck ++Determines whether to be strict about the identity of the GSSAPI acceptor ++a client authenticates against. If ++.Dq yes ++then the client must authenticate against the ++.Pa host ++service on the current hostname. If ++.Dq no ++then the client may authenticate against any service key stored in the ++machine's default store. This facility is provided to assist with operation ++on multi homed machines. ++The default is ++.Dq yes . ++Note that this option applies only to protocol version 2 GSSAPI connections, ++and setting it to ++.Dq no ++may only work with recent Kerberos GSSAPI libraries. ++.It Cm GSSAPIStoreCredentialsOnRekey ++Controls whether the user's GSSAPI credentials should be updated following a ++successful connection rekeying. This option can be used to accepted renewed ++or updated credentials from a compatible client. The default is ++.Dq no . + .It Cm HostbasedAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication together + with successful public key client host authentication is allowed +diff -up openssh-5.6p1/sshd_config.gsskex openssh-5.6p1/sshd_config +--- openssh-5.6p1/sshd_config.gsskex 2010-08-23 12:51:56.000000000 +0200 ++++ openssh-5.6p1/sshd_config 2010-08-23 12:51:59.000000000 +0200 +@@ -78,6 +78,8 @@ ChallengeResponseAuthentication no + GSSAPIAuthentication yes + #GSSAPICleanupCredentials yes + GSSAPICleanupCredentials yes ++#GSSAPIStrictAcceptorCheck yes ++#GSSAPIKeyExchange no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will +diff -up openssh-5.6p1/ssh-gss.h.gsskex openssh-5.6p1/ssh-gss.h +--- openssh-5.6p1/ssh-gss.h.gsskex 2007-06-12 15:40:39.000000000 +0200 ++++ openssh-5.6p1/ssh-gss.h 2010-08-23 12:51:59.000000000 +0200 +@@ -1,6 +1,6 @@ + /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -60,10 +60,22 @@ + + #define SSH_GSS_OIDTYPE 0x06 + ++#define SSH2_MSG_KEXGSS_INIT 30 ++#define SSH2_MSG_KEXGSS_CONTINUE 31 ++#define SSH2_MSG_KEXGSS_COMPLETE 32 ++#define SSH2_MSG_KEXGSS_HOSTKEY 33 ++#define SSH2_MSG_KEXGSS_ERROR 34 ++#define SSH2_MSG_KEXGSS_GROUPREQ 40 ++#define SSH2_MSG_KEXGSS_GROUP 41 ++#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" ++#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" ++#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" ++ + typedef struct { + char *filename; + char *envvar; + char *envval; ++ struct passwd *owner; + void *data; + } ssh_gssapi_ccache; + +@@ -71,8 +83,11 @@ typedef struct { + gss_buffer_desc displayname; + gss_buffer_desc exportedname; + gss_cred_id_t creds; ++ gss_name_t name; + struct ssh_gssapi_mech_struct *mech; + ssh_gssapi_ccache store; ++ int used; ++ int updated; + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +@@ -83,6 +98,7 @@ typedef struct ssh_gssapi_mech_struct { + int (*userok) (ssh_gssapi_client *, char *); + int (*localname) (ssh_gssapi_client *, char **); + void (*storecreds) (ssh_gssapi_client *); ++ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); + } ssh_gssapi_mech; + + typedef struct { +@@ -93,10 +109,11 @@ typedef struct { + gss_OID oid; /* client */ + gss_cred_id_t creds; /* server */ + gss_name_t client; /* server */ +- gss_cred_id_t client_creds; /* server */ ++ gss_cred_id_t client_creds; /* both */ + } Gssctxt; + + extern ssh_gssapi_mech *supported_mechs[]; ++extern Gssctxt *gss_kex_context; + + int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); + void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); +@@ -116,16 +133,30 @@ void ssh_gssapi_build_ctx(Gssctxt **); + void ssh_gssapi_delete_ctx(Gssctxt **); + OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); + void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); +-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); ++int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); ++OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); ++int ssh_gssapi_credentials_updated(Gssctxt *); + + /* In the server */ ++typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, ++ const char *); ++char *ssh_gssapi_client_mechanisms(const char *, const char *); ++char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, ++ const char *); ++gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); ++int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, ++ const char *); + OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +-int ssh_gssapi_userok(char *name); ++int ssh_gssapi_userok(char *name, struct passwd *); + OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); + void ssh_gssapi_do_child(char ***, u_int *); + void ssh_gssapi_cleanup_creds(void); + void ssh_gssapi_storecreds(void); + ++char *ssh_gssapi_server_mechanisms(void); ++int ssh_gssapi_oid_table_ok(); ++ ++int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); + #endif /* GSSAPI */ + + #endif /* _SSH_GSS_H */ diff --git a/openssh-5.6p1-keygen.patch b/openssh-5.6p1-keygen.patch new file mode 100644 index 0000000..9d7fce2 --- /dev/null +++ b/openssh-5.6p1-keygen.patch @@ -0,0 +1,80 @@ +diff -up openssh-5.6p1/ssh-keygen.0.keygen openssh-5.6p1/ssh-keygen.0 +--- openssh-5.6p1/ssh-keygen.0.keygen 2010-08-22 16:30:03.000000000 +0200 ++++ openssh-5.6p1/ssh-keygen.0 2010-08-23 12:37:19.000000000 +0200 +@@ -4,7 +4,7 @@ NAME + ssh-keygen - authentication key generation, management and conversion + + SYNOPSIS +- ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment] ++ ssh-keygen [-q] [-o] [-b bits] -t type [-N new_passphrase] [-C comment] + [-f output_keyfile] + ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile] + ssh-keygen -i [-m key_format] [-f input_keyfile] +@@ -232,6 +232,8 @@ DESCRIPTION + + -q Silence ssh-keygen. Used by /etc/rc when creating a new key. + ++ -o Overwrite the key without prompting user. ++ + -R hostname + Removes all keys belonging to hostname from a known_hosts file. + This option is useful to delete hashed hosts (see the -H option +diff -up openssh-5.6p1/ssh-keygen.1.keygen openssh-5.6p1/ssh-keygen.1 +--- openssh-5.6p1/ssh-keygen.1.keygen 2010-08-05 05:05:32.000000000 +0200 ++++ openssh-5.6p1/ssh-keygen.1 2010-08-23 12:36:25.000000000 +0200 +@@ -47,6 +47,7 @@ + .Bk -words + .Nm ssh-keygen + .Op Fl q ++.Op Fl o + .Op Fl b Ar bits + .Fl t Ar type + .Op Fl N Ar new_passphrase +@@ -397,6 +398,8 @@ Silence + Used by + .Pa /etc/rc + when creating a new key. ++.It Fl o ++Overwrite the key without prompting user. + .It Fl R Ar hostname + Removes all keys belonging to + .Ar hostname +diff -up openssh-5.6p1/ssh-keygen.c.keygen openssh-5.6p1/ssh-keygen.c +--- openssh-5.6p1/ssh-keygen.c.keygen 2010-08-05 05:05:32.000000000 +0200 ++++ openssh-5.6p1/ssh-keygen.c 2010-08-23 12:34:40.000000000 +0200 +@@ -72,6 +72,7 @@ int change_passphrase = 0; + int change_comment = 0; + + int quiet = 0; ++int overwrite = 0; + + int log_level = SYSLOG_LEVEL_INFO; + +@@ -1798,7 +1799,7 @@ main(int argc, char **argv) + exit(1); + } + +- while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" ++ while ((opt = getopt(argc, argv, "degiqopclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" + "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { + switch (opt) { + case 'b': +@@ -1878,6 +1879,9 @@ main(int argc, char **argv) + case 'q': + quiet = 1; + break; ++ case 'o': ++ overwrite = 1; ++ break; + case 'e': + case 'x': + /* export key */ +@@ -2124,7 +2128,7 @@ main(int argc, char **argv) + } + } + /* If the file already exists, ask the user to confirm. */ +- if (stat(identity_file, &st) >= 0) { ++ if (!overwrite && stat(identity_file, &st) >= 0) { + char yesno[3]; + printf("%s already exists.\n", identity_file); + printf("Overwrite (y/n)? "); diff --git a/openssh-5.6p1-kuserok.patch b/openssh-5.6p1-kuserok.patch new file mode 100644 index 0000000..7754032 --- /dev/null +++ b/openssh-5.6p1-kuserok.patch @@ -0,0 +1,132 @@ +diff -up openssh-5.6p1/auth-krb5.c.kuserok openssh-5.6p1/auth-krb5.c +--- openssh-5.6p1/auth-krb5.c.kuserok 2010-08-23 13:01:19.000000000 +0200 ++++ openssh-5.6p1/auth-krb5.c 2010-08-23 13:01:21.000000000 +0200 +@@ -146,9 +146,11 @@ auth_krb5_password(Authctxt *authctxt, c + if (problem) + goto out; + +- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { +- problem = -1; +- goto out; ++ if (options.use_kuserok) { ++ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { ++ problem = -1; ++ goto out; ++ } + } + + problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); +diff -up openssh-5.6p1/servconf.c.kuserok openssh-5.6p1/servconf.c +--- openssh-5.6p1/servconf.c.kuserok 2010-08-23 13:01:20.000000000 +0200 ++++ openssh-5.6p1/servconf.c 2010-08-23 13:02:14.000000000 +0200 +@@ -138,6 +138,7 @@ initialize_server_options(ServerOptions + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; + options->authorized_principals_file = NULL; ++ options->use_kuserok = -1; + } + + void +@@ -286,6 +287,8 @@ fill_default_server_options(ServerOption + if (use_privsep == -1) + use_privsep = 1; + ++ if (options->use_kuserok == -1) ++ options->use_kuserok = 1; + #ifndef HAVE_MMAP + if (use_privsep && options->compression == 1) { + error("This platform does not support both privilege " +@@ -307,7 +310,7 @@ typedef enum { + sPermitRootLogin, sLogFacility, sLogLevel, + sRhostsRSAAuthentication, sRSAAuthentication, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +- sKerberosGetAFSToken, ++ sKerberosGetAFSToken, sKerberosUseKuserok, + sKerberosTgtPassing, sChallengeResponseAuthentication, + sPasswordAuthentication, sKbdInteractiveAuthentication, + sListenAddress, sAddressFamily, +@@ -377,11 +380,13 @@ static struct { + #else + { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, + #endif ++ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL }, + #else + { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, + { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, + { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, + { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, ++ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL }, + #endif + { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, + { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, +@@ -1341,6 +1346,10 @@ process_server_config_line(ServerOptions + *activep = value; + break; + ++ case sKerberosUseKuserok: ++ intptr = &options->use_kuserok; ++ goto parse_flag; ++ + case sPermitOpen: + arg = strdelim(&cp); + if (!arg || *arg == '\0') +@@ -1525,6 +1534,7 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(x11_use_localhost); + M_CP_INTOPT(max_sessions); + M_CP_INTOPT(max_authtries); ++ M_CP_INTOPT(use_kuserok); + + M_CP_STROPT(banner); + if (preauth) +@@ -1745,6 +1755,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sUseDNS, o->use_dns); + dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); ++ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); + + /* string arguments */ + dump_cfg_string(sPidFile, o->pid_file); +diff -up openssh-5.6p1/servconf.h.kuserok openssh-5.6p1/servconf.h +--- openssh-5.6p1/servconf.h.kuserok 2010-08-23 13:01:20.000000000 +0200 ++++ openssh-5.6p1/servconf.h 2010-08-23 13:01:21.000000000 +0200 +@@ -157,6 +157,7 @@ typedef struct { + + int num_permitted_opens; + ++ int use_kuserok; + char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; +diff -up openssh-5.6p1/sshd_config.5.kuserok openssh-5.6p1/sshd_config.5 +--- openssh-5.6p1/sshd_config.5.kuserok 2010-08-23 13:01:21.000000000 +0200 ++++ openssh-5.6p1/sshd_config.5 2010-08-23 13:03:15.000000000 +0200 +@@ -564,6 +564,10 @@ Specifies whether to automatically destr + file on logout. + The default is + .Dq yes . ++.It Cm KerberosUseKuserok ++Specifies whether to look at .k5login file for user's aliases. ++The default is ++.Dq yes . + .It Cm KeyRegenerationInterval + In protocol version 1, the ephemeral server key is automatically regenerated + after this many seconds (if it has been used). +@@ -694,6 +698,7 @@ Available keywords are + .Cm HostbasedUsesNameFromPacketOnly , + .Cm KbdInteractiveAuthentication , + .Cm KerberosAuthentication , ++.Cm KerberosUseKuserok , + .Cm MaxAuthTries , + .Cm MaxSessions , + .Cm PubkeyAuthentication , +diff -up openssh-5.6p1/sshd_config.kuserok openssh-5.6p1/sshd_config +--- openssh-5.6p1/sshd_config.kuserok 2010-08-23 13:01:21.000000000 +0200 ++++ openssh-5.6p1/sshd_config 2010-08-23 13:01:21.000000000 +0200 +@@ -72,6 +72,7 @@ ChallengeResponseAuthentication no + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no ++#KerberosUseKuserok yes + + # GSSAPI options + #GSSAPIAuthentication no diff --git a/openssh-5.6p1-ldap.patch b/openssh-5.6p1-ldap.patch new file mode 100644 index 0000000..1010a8c --- /dev/null +++ b/openssh-5.6p1-ldap.patch @@ -0,0 +1,2859 @@ +diff -up openssh-5.6p1/configure.ac.ldap openssh-5.6p1/configure.ac +--- openssh-5.6p1/configure.ac.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/configure.ac 2010-08-23 12:28:11.000000000 +0200 +@@ -1358,6 +1358,106 @@ AC_ARG_WITH(authorized-keys-command, + ] + ) + ++# Check whether user wants LDAP support ++LDAP_MSG="no" ++INSTALL_SSH_LDAP_HELPER="" ++AC_ARG_WITH(ldap, ++ [ --with-ldap[[=PATH]] Enable LDAP pubkey support (optionally in PATH)], ++ [ ++ if test "x$withval" != "xno" ; then ++ ++ INSTALL_SSH_LDAP_HELPER="yes" ++ CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED" ++ ++ if test "x$withval" != "xyes" ; then ++ CPPFLAGS="$CPPFLAGS -I${withval}/include" ++ LDFLAGS="$LDFLAGS -L${withval}/lib" ++ fi ++ ++ AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support]) ++ LDAP_MSG="yes" ++ ++ AC_CHECK_HEADERS(lber.h) ++ AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate )) ++ AC_CHECK_HEADERS(ldap_ssl.h) ++ ++ AC_ARG_WITH(ldap-lib, ++ [ --with-ldap-lib=type select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]]) ++ ++ if test -z "$with_ldap_lib"; then ++ with_ldap_lib=auto ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then ++ AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes) ++ AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then ++ AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then ++ AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes) ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes) ++ fi ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes) ++ fi ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes) ++ fi ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then ++ AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib"; then ++ AC_MSG_ERROR(could not locate a valid LDAP library) ++ fi ++ ++ AC_MSG_CHECKING([for working LDAP support]) ++ AC_TRY_COMPILE( ++ [#include ++ #include ], ++ [(void)ldap_init(0, 0);], ++ [AC_MSG_RESULT(yes)], ++ [ ++ AC_MSG_RESULT(no) ++ AC_MSG_ERROR([** Incomplete or missing ldap libraries **]) ++ ]) ++ AC_CHECK_FUNCS( \ ++ ldap_init \ ++ ldap_get_lderrno \ ++ ldap_set_lderrno \ ++ ldap_parse_result \ ++ ldap_memfree \ ++ ldap_controls_free \ ++ ldap_set_option \ ++ ldap_get_option \ ++ ldapssl_init \ ++ ldap_start_tls_s \ ++ ldap_pvt_tls_set_option \ ++ ldap_initialize \ ++ ) ++ AC_CHECK_FUNCS(ldap_set_rebind_proc, ++ AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc]) ++ AC_TRY_COMPILE( ++ [#include ++ #include ], ++ [ldap_set_rebind_proc(0, 0, 0);], ++ [ac_cv_ldap_set_rebind_proc=3], ++ [ac_cv_ldap_set_rebind_proc=2]) ++ AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc) ++ AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc]) ++ ) ++ fi ++ ] ++) ++AC_SUBST(INSTALL_SSH_LDAP_HELPER) ++ + dnl Checks for library functions. Please keep in alphabetical order + AC_CHECK_FUNCS( \ + arc4random \ +diff -up openssh-5.6p1/ldapbody.c.ldap openssh-5.6p1/ldapbody.c +--- openssh-5.6p1/ldapbody.c.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapbody.c 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,494 @@ ++/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "ldapincludes.h" ++#include "log.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include "ldapmisc.h" ++#include "ldapbody.h" ++#include ++#include ++ ++#define LDAPSEARCH_FORMAT "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)" ++#define PUBKEYATTR "sshPublicKey" ++#define LDAP_LOGFILE "%s/ldap.%d" ++ ++static FILE *logfile = NULL; ++static LDAP *ld; ++ ++static char *attrs[] = { ++ PUBKEYATTR, ++ NULL ++}; ++ ++void ++ldap_checkconfig (void) ++{ ++#ifdef HAVE_LDAP_INITIALIZE ++ if (options.host == NULL && options.uri == NULL) ++#else ++ if (options.host == NULL) ++#endif ++ fatal ("missing \"host\" in config file"); ++} ++ ++#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) ++static int ++_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid) ++{ ++ struct timeval timeout; ++ int rc; ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ LDAPMessage *result; ++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ ++ ++ debug2 ("Doing LDAP rebind to %s", options.binddn); ++ if (options.ssl == SSL_START_TLS) { ++ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) { ++ error ("ldap_starttls_s: %s", ldap_err2string (rc)); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ } ++ ++#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE) ++ return ldap_simple_bind_s (ld, options.binddn, options.bindpw); ++#else ++ if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0) ++ fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); ++ ++ timeout.tv_sec = options.bind_timelimit; ++ timeout.tv_usec = 0; ++ result = NULL; ++ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { ++ error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); ++ ldap_msgfree (result); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ debug3 ("LDAP rebind to %s succesfull", options.binddn); ++ return rc; ++#endif ++} ++#else ++ ++static int ++_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit) ++{ ++ if (freeit) ++ return LDAP_SUCCESS; ++ ++ *whop = strdup (options.binddn); ++ *credp = strdup (options.bindpw); ++ *methodp = LDAP_AUTH_SIMPLE; ++ debug2 ("Doing LDAP rebind for %s", *whop); ++ return LDAP_SUCCESS; ++} ++#endif ++ ++void ++ldap_do_connect(void) ++{ ++ int rc, msgid, ld_errno = 0; ++ struct timeval timeout; ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ int parserc; ++ LDAPMessage *result; ++ LDAPControl **controls; ++ int reconnect = 0; ++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ ++ ++ debug ("LDAP do connect"); ++ ++retry: ++ if (reconnect) { ++ debug3 ("Reconnecting with ld_errno %d", ld_errno); ++ if (options.bind_policy == 0 || ++ (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) || ++ reconnect > 5) ++ fatal ("Cannot connect to LDAP server"); ++ ++ if (reconnect > 1) ++ sleep (reconnect - 1); ++ ++ if (ld != NULL) { ++ ldap_unbind (ld); ++ ld = NULL; ++ } ++ logit("reconnecting to LDAP server..."); ++ } ++ ++ if (ld == NULL) { ++ int rc; ++ struct timeval tv; ++ ++#ifdef HAVE_LDAP_SET_OPTION ++ if (options.debug > 0) { ++#ifdef LBER_OPT_LOG_PRINT_FILE ++ if (options.logdir) { ++ char *logfilename; ++ int logfilenamelen; ++ ++ logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir); ++ logfilename = xmalloc (logfilenamelen); ++ snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ()); ++ logfilename[logfilenamelen - 1] = 0; ++ if ((logfile = fopen (logfilename, "a")) == NULL) ++ fatal ("cannot append to %s: %s", logfilename, strerror (errno)); ++ debug3 ("LDAP debug into %s", logfilename); ++ xfree (logfilename); ++ ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile); ++ } ++#endif ++ if (options.debug) { ++#ifdef LBER_OPT_DEBUG_LEVEL ++ ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug); ++#endif /* LBER_OPT_DEBUG_LEVEL */ ++#ifdef LDAP_OPT_DEBUG_LEVEL ++ ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug); ++#endif /* LDAP_OPT_DEBUG_LEVEL */ ++ debug3 ("Set LDAP debug to %d", options.debug); ++ } ++ } ++#endif /* HAVE_LDAP_SET_OPTION */ ++ ++ ld = NULL; ++#ifdef HAVE_LDAPSSL_INIT ++ if (options.host != NULL) { ++ if (options.ssl_on == SSL_LDAPS) { ++ if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS) ++ fatal ("ldapssl_client_init %s", ldap_err2string (rc)); ++ debug3 ("LDAPssl client init"); ++ } ++ ++ if (options.ssl_on != SSL_OFF) { ++ if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL) ++ fatal ("ldapssl_init failed"); ++ debug3 ("LDAPssl init"); ++ } ++ } ++#endif /* HAVE_LDAPSSL_INIT */ ++ ++ /* continue with opening */ ++ if (ld == NULL) { ++#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) ++ /* Some global TLS-specific options need to be set before we create our ++ * session context, so we set them here. */ ++ ++#ifdef LDAP_OPT_X_TLS_RANDOM_FILE ++ /* rand file */ ++ if (options.tls_randfile != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE, ++ options.tls_randfile)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS random file %s", options.tls_randfile); ++ } ++#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */ ++ ++ /* ca cert file */ ++ if (options.tls_cacertfile != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, ++ options.tls_cacertfile)) != LDAP_SUCCESS) ++ error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile); ++ } ++ ++ /* ca cert directory */ ++ if (options.tls_cacertdir != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, ++ options.tls_cacertdir)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir); ++ } ++ ++ /* require cert? */ ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, ++ &options.tls_checkpeer)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS check peer to %d ", options.tls_checkpeer); ++ ++ /* set cipher suite, certificate and private key: */ ++ if (options.tls_ciphers != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, ++ options.tls_ciphers)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS ciphers to %s ", options.tls_ciphers); ++ } ++ ++ /* cert file */ ++ if (options.tls_cert != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, ++ options.tls_cert)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS cert file %s ", options.tls_cert); ++ } ++ ++ /* key file */ ++ if (options.tls_key != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, ++ options.tls_key)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS key file %s ", options.tls_key); ++ } ++#endif ++#ifdef HAVE_LDAP_INITIALIZE ++ if (options.uri != NULL) { ++ if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS) ++ fatal ("ldap_initialize %s", ldap_err2string (rc)); ++ debug3 ("LDAP initialize %s", options.uri); ++ } ++ } ++#endif /* HAVE_LDAP_INTITIALIZE */ ++ ++ /* continue with opening */ ++ if ((ld == NULL) && (options.host != NULL)) { ++#ifdef HAVE_LDAP_INIT ++ if ((ld = ldap_init (options.host, options.port)) == NULL) ++ fatal ("ldap_init failed"); ++ debug3 ("LDAP init %s:%d", options.host, options.port); ++#else ++ if ((ld = ldap_open (options.host, options.port)) == NULL) ++ fatal ("ldap_open failed"); ++ debug3 ("LDAP open %s:%d", options.host, options.port); ++#endif /* HAVE_LDAP_INIT */ ++ } ++ ++ if (ld == NULL) ++ fatal ("no way to open ldap"); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) ++ if (options.ssl == SSL_LDAPS) { ++ if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc)); ++ debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer); ++ } ++#endif /* LDAP_OPT_X_TLS */ ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION) ++ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, ++ &options.ldap_version); ++#else ++ ld->ld_version = options.ldap_version; ++#endif ++ debug3 ("LDAP set version to %d", options.ldap_version); ++ ++#if LDAP_SET_REBIND_PROC_ARGS == 3 ++ ldap_set_rebind_proc (ld, _rebind_proc, NULL); ++#elif LDAP_SET_REBIND_PROC_ARGS == 2 ++ ldap_set_rebind_proc (ld, _rebind_proc); ++#else ++#warning unknown LDAP_SET_REBIND_PROC_ARGS ++#endif ++ debug3 ("LDAP set rebind proc"); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF) ++ (void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref); ++#else ++ ld->ld_deref = options.deref; ++#endif ++ debug3 ("LDAP set deref to %d", options.deref); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT) ++ (void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT, ++ &options.timelimit); ++#else ++ ld->ld_timelimit = options.timelimit; ++#endif ++ debug3 ("LDAP set timelimit to %d", options.timelimit); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT) ++ /* ++ * This is a new option in the Netscape SDK which sets ++ * the TCP connect timeout. For want of a better value, ++ * we use the bind_timelimit to control this. ++ */ ++ timeout = options.bind_timelimit * 1000; ++ (void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout); ++ debug3 ("LDAP set opt connect timeout to %d", timeout); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT) ++ tv.tv_sec = options.bind_timelimit; ++ tv.tv_usec = 0; ++ (void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); ++ debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS) ++ (void) ldap_set_option (ld, LDAP_OPT_REFERRALS, ++ options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF); ++ debug3 ("LDAP set referrals to %d", options.referrals); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART) ++ (void) ldap_set_option (ld, LDAP_OPT_RESTART, ++ options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF); ++ debug3 ("LDAP set restart to %d", options.restart); ++#endif ++ ++#ifdef HAVE_LDAP_START_TLS_S ++ if (options.ssl == SSL_START_TLS) { ++ int version; ++ ++ if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version) ++ == LDAP_SUCCESS) { ++ if (version < LDAP_VERSION3) { ++ version = LDAP_VERSION3; ++ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, ++ &version); ++ debug3 ("LDAP set version to %d", version); ++ } ++ } ++ ++ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) ++ fatal ("ldap_starttls_s: %s", ldap_err2string (rc)); ++ debug3 ("LDAP start TLS"); ++ } ++#endif /* HAVE_LDAP_START_TLS_S */ ++ } ++ ++ if ((msgid = ldap_simple_bind (ld, options.binddn, ++ options.bindpw)) == -1) { ++ ld_errno = ldap_get_lderrno (ld, 0, 0); ++ ++ error ("ldap_simple_bind %s", ldap_err2string (ld_errno)); ++ reconnect++; ++ goto retry; ++ } ++ debug3 ("LDAP simple bind (%s)", options.binddn); ++ ++ timeout.tv_sec = options.bind_timelimit; ++ timeout.tv_usec = 0; ++ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { ++ ld_errno = ldap_get_lderrno (ld, 0, 0); ++ ++ error ("ldap_result %s", ldap_err2string (ld_errno)); ++ reconnect++; ++ goto retry; ++ } ++ debug3 ("LDAP result in time"); ++ ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ controls = NULL; ++ if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS) ++ fatal ("ldap_parse_result %s", ldap_err2string (parserc)); ++ debug3 ("LDAP parse result OK"); ++ ++ if (controls != NULL) { ++ ldap_controls_free (controls); ++ } ++#else ++ rc = ldap_result2error (session->ld, result, TRUE); ++#endif ++ if (rc != LDAP_SUCCESS) ++ fatal ("error trying to bind as user \"%s\" (%s)", ++ options.binddn, ldap_err2string (rc)); ++ ++ debug2 ("LDAP do connect OK"); ++} ++ ++void ++process_user (const char *user, FILE *output) ++{ ++ LDAPMessage *res, *e; ++ char *buffer; ++ int bufflen, rc, i; ++ struct timeval timeout; ++ ++ debug ("LDAP process user"); ++ ++ /* quick check for attempts to be evil */ ++ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) || ++ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) { ++ logit ("illegal user name %s not processed", user); ++ return; ++ } ++ ++ /* build filter for LDAP request */ ++ bufflen = strlen (LDAPSEARCH_FORMAT) + strlen (user); ++ if (options.ssh_filter != NULL) ++ bufflen += strlen (options.ssh_filter); ++ buffer = xmalloc (bufflen); ++ snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, user, (options.ssh_filter != NULL) ? options.ssh_filter : NULL); ++ buffer[bufflen - 1] = 0; ++ ++ debug3 ("LDAP search scope = %d %s", options.scope, buffer); ++ ++ timeout.tv_sec = options.timelimit; ++ timeout.tv_usec = 0; ++ if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) { ++ error ("ldap_search_st(): %s", ldap_err2string (rc)); ++ xfree (buffer); ++ return; ++ } ++ ++ /* free */ ++ xfree (buffer); ++ ++ for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) { ++ int num; ++ struct berval **keys; ++ ++ keys = ldap_get_values_len(ld, e, PUBKEYATTR); ++ num = ldap_count_values_len(keys); ++ for (i = 0 ; i < num ; i++) { ++ char *cp; //, *options = NULL; ++ ++ for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++); ++ if (!*cp || *cp == '\n' || *cp == '#') ++ continue; ++ ++ /* We have found the desired key. */ ++ fprintf (output, "%s\n", keys[i]->bv_val); ++ } ++ ++ ldap_value_free_len(keys); ++ } ++ ++ ldap_msgfree(res); ++ debug2 ("LDAP process user finished"); ++} ++ ++void ++ldap_do_close(void) ++{ ++ int rc; ++ ++ debug ("LDAP do close"); ++ if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS) ++ fatal ("ldap_unbind_ext: %s", ++ ldap_err2string (rc)); ++ ++ ld = NULL; ++ debug2 ("LDAP do close OK"); ++ return; ++} ++ +diff -up openssh-5.6p1/ldapbody.h.ldap openssh-5.6p1/ldapbody.h +--- openssh-5.6p1/ldapbody.h.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapbody.h 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,37 @@ ++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LDAPBODY_H ++#define LDAPBODY_H ++ ++#include ++ ++void ldap_checkconfig(void); ++void ldap_do_connect(void); ++void process_user(const char *, FILE *); ++void ldap_do_close(void); ++ ++#endif /* LDAPBODY_H */ ++ +diff -up openssh-5.6p1/ldapconf.c.ldap openssh-5.6p1/ldapconf.c +--- openssh-5.6p1/ldapconf.c.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapconf.c 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,682 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "ldapincludes.h" ++#include "ldap-helper.h" ++#include "log.h" ++#include "misc.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include ++#include ++ ++/* Keyword tokens. */ ++ ++typedef enum { ++ lBadOption, ++ lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN, ++ lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit, ++ lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals, ++ lRestart, lTLS_CheckPeer, lTLS_CaCertFile, ++ lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key, ++ lTLS_RandFile, lLogDir, lDebug, lSSH_Filter, ++ lDeprecated, lUnsupported ++} OpCodes; ++ ++/* Textual representations of the tokens. */ ++ ++static struct { ++ const char *name; ++ OpCodes opcode; ++} keywords[] = { ++ { "URI", lURI }, ++ { "Base", lBase }, ++ { "BindDN", lBindDN }, ++ { "BindPW", lBindPW }, ++ { "RootBindDN", lRootBindDN }, ++ { "Host", lHost }, ++ { "Port", lPort }, ++ { "Scope", lScope }, ++ { "Deref", lDeref }, ++ { "TimeLimit", lTimeLimit }, ++ { "TimeOut", lTimeLimit }, ++ { "Bind_Timelimit", lBind_TimeLimit }, ++ { "Network_TimeOut", lBind_TimeLimit }, ++/* ++ * Todo ++ * SIZELIMIT ++ */ ++ { "Ldap_Version", lLdap_Version }, ++ { "Version", lLdap_Version }, ++ { "Bind_Policy", lBind_Policy }, ++ { "SSLPath", lSSLPath }, ++ { "SSL", lSSL }, ++ { "Referrals", lReferrals }, ++ { "Restart", lRestart }, ++ { "TLS_CheckPeer", lTLS_CheckPeer }, ++ { "TLS_ReqCert", lTLS_CheckPeer }, ++ { "TLS_CaCertFile", lTLS_CaCertFile }, ++ { "TLS_CaCert", lTLS_CaCertFile }, ++ { "TLS_CaCertDir", lTLS_CaCertDir }, ++ { "TLS_Ciphers", lTLS_Ciphers }, ++ { "TLS_Cipher_Suite", lTLS_Ciphers }, ++ { "TLS_Cert", lTLS_Cert }, ++ { "TLS_Certificate", lTLS_Cert }, ++ { "TLS_Key", lTLS_Key }, ++ { "TLS_RandFile", lTLS_RandFile }, ++/* ++ * Todo ++ * TLS_CRLCHECK ++ * TLS_CRLFILE ++ */ ++ { "LogDir", lLogDir }, ++ { "Debug", lDebug }, ++ { "SSH_Filter", lSSH_Filter }, ++ { NULL, lBadOption } ++}; ++ ++/* Configuration ptions. */ ++ ++Options options; ++ ++/* ++ * Returns the number of the token pointed to by cp or oBadOption. ++ */ ++ ++static OpCodes ++parse_token(const char *cp, const char *filename, int linenum) ++{ ++ u_int i; ++ ++ for (i = 0; keywords[i].name; i++) ++ if (strcasecmp(cp, keywords[i].name) == 0) ++ return keywords[i].opcode; ++ ++ if (config_warning_config_file) ++ logit("%s: line %d: Bad configuration option: %s", ++ filename, linenum, cp); ++ return lBadOption; ++} ++ ++/* ++ * Processes a single option line as used in the configuration files. This ++ * only sets those values that have not already been set. ++ */ ++#define WHITESPACE " \t\r\n" ++ ++static int ++process_config_line(char *line, const char *filename, int linenum) ++{ ++ char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg; ++ char *rootbinddn = NULL; ++ int opcode, *intptr, value; ++ size_t len; ++ ++ /* Strip trailing whitespace */ ++ for (len = strlen(line) - 1; len > 0; len--) { ++ if (strchr(WHITESPACE, line[len]) == NULL) ++ break; ++ line[len] = '\0'; ++ } ++ ++ s = line; ++ /* Get the keyword. (Each line is supposed to begin with a keyword). */ ++ if ((keyword = strdelim(&s)) == NULL) ++ return 0; ++ /* Ignore leading whitespace. */ ++ if (*keyword == '\0') ++ keyword = strdelim(&s); ++ if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') ++ return 0; ++ ++ opcode = parse_token(keyword, filename, linenum); ++ ++ switch (opcode) { ++ case lBadOption: ++ /* don't panic, but count bad options */ ++ return -1; ++ /* NOTREACHED */ ++ ++ case lHost: ++ xstringptr = &options.host; ++parse_xstring: ++ if (!s || *s == '\0') ++ fatal("%s line %d: missing dn",filename,linenum); ++ if (*xstringptr == NULL) ++ *xstringptr = xstrdup(s); ++ return 0; ++ ++ case lURI: ++ xstringptr = &options.uri; ++ goto parse_xstring; ++ ++ case lBase: ++ xstringptr = &options.base; ++ goto parse_xstring; ++ ++ case lBindDN: ++ xstringptr = &options.binddn; ++ goto parse_xstring; ++ ++ case lBindPW: ++ charptr = &options.bindpw; ++parse_string: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", filename, linenum); ++ if (*charptr == NULL) ++ *charptr = xstrdup(arg); ++ break; ++ ++ case lRootBindDN: ++ xstringptr = &rootbinddn; ++ goto parse_xstring; ++ ++ case lScope: ++ intptr = &options.scope; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing sub/one/base argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp (arg, "sub") == 0 || strcasecmp (arg, "subtree") == 0) ++ value = LDAP_SCOPE_SUBTREE; ++ else if (strcasecmp (arg, "one") == 0) ++ value = LDAP_SCOPE_ONELEVEL; ++ else if (strcasecmp (arg, "base") == 0) ++ value = LDAP_SCOPE_BASE; ++ else ++ fatal("%.200s line %d: Bad sub/one/base argument.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lDeref: ++ intptr = &options.scope; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing never/searching/finding/always argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (!strcasecmp (arg, "never")) ++ value = LDAP_DEREF_NEVER; ++ else if (!strcasecmp (arg, "searching")) ++ value = LDAP_DEREF_SEARCHING; ++ else if (!strcasecmp (arg, "finding")) ++ value = LDAP_DEREF_FINDING; ++ else if (!strcasecmp (arg, "always")) ++ value = LDAP_DEREF_ALWAYS; ++ else ++ fatal("%.200s line %d: Bad never/searching/finding/always argument.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lPort: ++ intptr = &options.port; ++parse_int: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", filename, linenum); ++ if (arg[0] < '0' || arg[0] > '9') ++ fatal("%.200s line %d: Bad number.", filename, linenum); ++ ++ /* Octal, decimal, or hex format? */ ++ value = strtol(arg, &endofnumber, 0); ++ if (arg == endofnumber) ++ fatal("%.200s line %d: Bad number.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lTimeLimit: ++ intptr = &options.timelimit; ++parse_time: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: missing time value.", ++ filename, linenum); ++ if ((value = convtime(arg)) == -1) ++ fatal("%s line %d: invalid time value.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lBind_TimeLimit: ++ intptr = &options.bind_timelimit; ++ goto parse_time; ++ ++ case lLdap_Version: ++ intptr = &options.ldap_version; ++ goto parse_int; ++ ++ case lBind_Policy: ++ intptr = &options.bind_policy; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing soft/hard argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "hard_open") == 0 || strcasecmp(arg, "hard_init") == 0) ++ value = 1; ++ else if (strcasecmp(arg, "soft") == 0) ++ value = 0; ++ else ++ fatal("%.200s line %d: Bad soft/hard argument.", filename, linenum); ++ if (*intptr == -1) ++ break; ++ ++ case lSSLPath: ++ charptr = &options.sslpath; ++ goto parse_string; ++ ++ case lSSL: ++ intptr = &options.ssl; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing yes/no/start_tls argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) ++ value = SSL_LDAPS; ++ else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) ++ value = SSL_OFF; ++ else if (!strcasecmp (arg, "start_tls")) ++ value = SSL_START_TLS; ++ else ++ fatal("%.200s line %d: Bad yes/no/start_tls argument.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lReferrals: ++ intptr = &options.referrals; ++parse_flag: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) ++ value = 1; ++ else if (strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) ++ value = 0; ++ else ++ fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lRestart: ++ intptr = &options.restart; ++ goto parse_flag; ++ ++ case lTLS_CheckPeer: ++ intptr = &options.tls_checkpeer; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "never") == 0 || strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0 || strcasecmp(arg, "off") == 0) ++ value = LDAP_OPT_X_TLS_NEVER; ++ else if (strcasecmp(arg, "hard") == 0 || strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0 || strcasecmp(arg, "on") == 0) ++ value = LDAP_OPT_X_TLS_HARD; ++ else if (strcasecmp(arg, "demand") == 0) ++ value = LDAP_OPT_X_TLS_DEMAND; ++ else if (strcasecmp(arg, "allow") == 0) ++ value = LDAP_OPT_X_TLS_ALLOW; ++ else if (strcasecmp(arg, "try") == 0) ++ value = LDAP_OPT_X_TLS_TRY; ++ else ++ fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", filename, linenum); ++ if (*intptr == -1) ++ break; ++ ++ case lTLS_CaCertFile: ++ charptr = &options.tls_cacertfile; ++ goto parse_string; ++ ++ case lTLS_CaCertDir: ++ charptr = &options.tls_cacertdir; ++ goto parse_string; ++ ++ case lTLS_Ciphers: ++ xstringptr = &options.tls_ciphers; ++ goto parse_xstring; ++ ++ case lTLS_Cert: ++ charptr = &options.tls_cert; ++ goto parse_string; ++ ++ case lTLS_Key: ++ charptr = &options.tls_key; ++ goto parse_string; ++ ++ case lTLS_RandFile: ++ charptr = &options.tls_randfile; ++ goto parse_string; ++ ++ case lLogDir: ++ charptr = &options.logdir; ++ goto parse_string; ++ ++ case lDebug: ++ intptr = &options.debug; ++ goto parse_int; ++ ++ case lSSH_Filter: ++ xstringptr = &options.ssh_filter; ++ goto parse_xstring; ++ ++ case lDeprecated: ++ debug("%s line %d: Deprecated option \"%s\"", ++ filename, linenum, keyword); ++ return 0; ++ ++ case lUnsupported: ++ error("%s line %d: Unsupported option \"%s\"", ++ filename, linenum, keyword); ++ return 0; ++ ++ default: ++ fatal("process_config_line: Unimplemented opcode %d", opcode); ++ } ++ ++ /* Check that there is no garbage at end of line. */ ++ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { ++ fatal("%.200s line %d: garbage at end of line; \"%.200s\".", ++ filename, linenum, arg); ++ } ++ return 0; ++} ++ ++/* ++ * Reads the config file and modifies the options accordingly. Options ++ * should already be initialized before this call. This never returns if ++ * there is an error. If the file does not exist, this returns 0. ++ */ ++ ++void ++read_config_file(const char *filename) ++{ ++ FILE *f; ++ char line[1024]; ++ int active, linenum; ++ int bad_options = 0; ++ struct stat sb; ++ ++ if ((f = fopen(filename, "r")) == NULL) ++ fatal("fopen %s: %s", filename, strerror(errno)); ++ ++ if (fstat(fileno(f), &sb) == -1) ++ fatal("fstat %s: %s", filename, strerror(errno)); ++ if (((sb.st_uid != 0 && sb.st_uid != getuid()) || ++ (sb.st_mode & 022) != 0)) ++ fatal("Bad owner or permissions on %s", filename); ++ ++ debug("Reading configuration data %.200s", filename); ++ ++ /* ++ * Mark that we are now processing the options. This flag is turned ++ * on/off by Host specifications. ++ */ ++ active = 1; ++ linenum = 0; ++ while (fgets(line, sizeof(line), f)) { ++ /* Update line number counter. */ ++ linenum++; ++ if (process_config_line(line, filename, linenum) != 0) ++ bad_options++; ++ } ++ fclose(f); ++ if ((bad_options > 0) && config_exclusive_config_file) ++ fatal("%s: terminating, %d bad configuration options", ++ filename, bad_options); ++} ++ ++/* ++ * Initializes options to special values that indicate that they have not yet ++ * been set. Read_config_file will only set options with this value. Options ++ * are processed in the following order: command line, user config file, ++ * system config file. Last, fill_default_options is called. ++ */ ++ ++void ++initialize_options(void) ++{ ++ memset(&options, 'X', sizeof(options)); ++ options.host = NULL; ++ options.uri = NULL; ++ options.base = NULL; ++ options.binddn = NULL; ++ options.bindpw = NULL; ++ options.scope = -1; ++ options.deref = -1; ++ options.port = -1; ++ options.timelimit = -1; ++ options.bind_timelimit = -1; ++ options.ldap_version = -1; ++ options.bind_policy = -1; ++ options.sslpath = NULL; ++ options.ssl = -1; ++ options.referrals = -1; ++ options.restart = -1; ++ options.tls_checkpeer = -1; ++ options.tls_cacertfile = NULL; ++ options.tls_cacertdir = NULL; ++ options.tls_ciphers = NULL; ++ options.tls_cert = NULL; ++ options.tls_key = NULL; ++ options.tls_randfile = NULL; ++ options.logdir = NULL; ++ options.debug = -1; ++ options.ssh_filter = NULL; ++} ++ ++/* ++ * Called after processing other sources of option data, this fills those ++ * options for which no value has been specified with their default values. ++ */ ++ ++void ++fill_default_options(void) ++{ ++ if (options.uri != NULL) { ++ LDAPURLDesc *ludp; ++ ++ if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) { ++ if (options.ssl == -1) { ++ if (strcmp (ludp->lud_scheme, "ldap") == 0) ++ options.ssl = 2; ++ if (strcmp (ludp->lud_scheme, "ldapi") == 0) ++ options.ssl = 0; ++ else if (strcmp (ludp->lud_scheme, "ldaps") == 0) ++ options.ssl = 1; ++ } ++ if (options.host == NULL) ++ options.host = xstrdup (ludp->lud_host); ++ if (options.port == -1) ++ options.port = ludp->lud_port; ++ ++ ldap_free_urldesc (ludp); ++ } ++ } ++ if (options.ssl == -1) ++ options.ssl = SSL_START_TLS; ++ if (options.port == -1) ++ options.port = (options.ssl == 0) ? 389 : 636; ++ if (options.uri == NULL) { ++ int len; ++#define MAXURILEN 4096 ++ ++ options.uri = xmalloc (MAXURILEN); ++ len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d", ++ (options.ssl == 0) ? "" : "s", options.host, options.port); ++ options.uri[MAXURILEN - 1] = 0; ++ options.uri = xrealloc (options.uri, len + 1, 1); ++ } ++ if (options.binddn == NULL) ++ options.binddn = ""; ++ if (options.bindpw == NULL) ++ options.bindpw = ""; ++ if (options.scope == -1) ++ options.scope = LDAP_SCOPE_SUBTREE; ++ if (options.deref == -1) ++ options.deref = LDAP_DEREF_NEVER; ++ if (options.timelimit == -1) ++ options.timelimit = 10; ++ if (options.bind_timelimit == -1) ++ options.bind_timelimit = 10; ++ if (options.ldap_version == -1) ++ options.ldap_version = 3; ++ if (options.bind_policy == -1) ++ options.bind_policy = 1; ++ if (options.referrals == -1) ++ options.referrals = 1; ++ if (options.restart == -1) ++ options.restart = 1; ++ if (options.tls_checkpeer == -1) ++ options.tls_checkpeer = LDAP_OPT_X_TLS_HARD; ++ if (options.debug == -1) ++ options.debug = 0; ++ if (options.ssh_filter == NULL) ++ options.ssh_filter = ""; ++} ++ ++static const char * ++lookup_opcode_name(OpCodes code) ++{ ++ u_int i; ++ ++ for (i = 0; keywords[i].name != NULL; i++) ++ if (keywords[i].opcode == code) ++ return(keywords[i].name); ++ return "UNKNOWN"; ++} ++ ++static void ++dump_cfg_string(OpCodes code, const char *val) ++{ ++ if (val == NULL) ++ debug3("%s ", lookup_opcode_name(code)); ++ else ++ debug3("%s %s", lookup_opcode_name(code), val); ++} ++ ++static void ++dump_cfg_int(OpCodes code, int val) ++{ ++ if (val == -1) ++ debug3("%s ", lookup_opcode_name(code)); ++ else ++ debug3("%s %d", lookup_opcode_name(code), val); ++} ++ ++struct names { ++ int value; ++ char *name; ++}; ++ ++static void ++dump_cfg_namedint(OpCodes code, int val, struct names *names) ++{ ++ u_int i; ++ ++ if (val == -1) ++ debug3("%s ", lookup_opcode_name(code)); ++ else { ++ for (i = 0; names[i].value != -1; i++) ++ if (names[i].value == val) { ++ debug3("%s %s", lookup_opcode_name(code), names[i].name); ++ return; ++ } ++ debug3("%s unknown: %d", lookup_opcode_name(code), val); ++ } ++} ++ ++static struct names _yesnotls[] = { ++ { 0, "No" }, ++ { 1, "Yes" }, ++ { 2, "Start_TLS" }, ++ { -1, NULL }}; ++ ++static struct names _scope[] = { ++ { LDAP_SCOPE_BASE, "Base" }, ++ { LDAP_SCOPE_ONELEVEL, "One" }, ++ { LDAP_SCOPE_SUBTREE, "Sub"}, ++ { -1, NULL }}; ++ ++static struct names _deref[] = { ++ { LDAP_DEREF_NEVER, "Never" }, ++ { LDAP_DEREF_SEARCHING, "Searching" }, ++ { LDAP_DEREF_FINDING, "Finding" }, ++ { LDAP_DEREF_ALWAYS, "Always" }, ++ { -1, NULL }}; ++ ++static struct names _yesno[] = { ++ { 0, "No" }, ++ { 1, "Yes" }, ++ { -1, NULL }}; ++ ++static struct names _bindpolicy[] = { ++ { 0, "Soft" }, ++ { 1, "Hard" }, ++ { -1, NULL }}; ++ ++static struct names _checkpeer[] = { ++ { LDAP_OPT_X_TLS_NEVER, "Never" }, ++ { LDAP_OPT_X_TLS_HARD, "Hard" }, ++ { LDAP_OPT_X_TLS_DEMAND, "Demand" }, ++ { LDAP_OPT_X_TLS_ALLOW, "Allow" }, ++ { LDAP_OPT_X_TLS_TRY, "TRY" }, ++ { -1, NULL }}; ++ ++void ++dump_config(void) ++{ ++ dump_cfg_string(lURI, options.uri); ++ dump_cfg_string(lHost, options.host); ++ dump_cfg_int(lPort, options.port); ++ dump_cfg_namedint(lSSL, options.ssl, _yesnotls); ++ dump_cfg_int(lLdap_Version, options.ldap_version); ++ dump_cfg_int(lTimeLimit, options.timelimit); ++ dump_cfg_int(lBind_TimeLimit, options.bind_timelimit); ++ dump_cfg_string(lBase, options.base); ++ dump_cfg_string(lBindDN, options.binddn); ++ dump_cfg_string(lBindPW, options.bindpw); ++ dump_cfg_namedint(lScope, options.scope, _scope); ++ dump_cfg_namedint(lDeref, options.deref, _deref); ++ dump_cfg_namedint(lReferrals, options.referrals, _yesno); ++ dump_cfg_namedint(lRestart, options.restart, _yesno); ++ dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy); ++ dump_cfg_string(lSSLPath, options.sslpath); ++ dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer); ++ dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile); ++ dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir); ++ dump_cfg_string(lTLS_Ciphers, options.tls_ciphers); ++ dump_cfg_string(lTLS_Cert, options.tls_cert); ++ dump_cfg_string(lTLS_Key, options.tls_key); ++ dump_cfg_string(lTLS_RandFile, options.tls_randfile); ++ dump_cfg_string(lLogDir, options.logdir); ++ dump_cfg_int(lDebug, options.debug); ++ dump_cfg_string(lSSH_Filter, options.ssh_filter); ++} ++ +diff -up openssh-5.6p1/ldapconf.h.ldap openssh-5.6p1/ldapconf.h +--- openssh-5.6p1/ldapconf.h.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapconf.h 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,71 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LDAPCONF_H ++#define LDAPCONF_H ++ ++#define SSL_OFF 0 ++#define SSL_LDAPS 1 ++#define SSL_START_TLS 2 ++ ++/* Data structure for representing option data. */ ++ ++typedef struct { ++ char *host; ++ char *uri; ++ char *base; ++ char *binddn; ++ char *bindpw; ++ int scope; ++ int deref; ++ int port; ++ int timelimit; ++ int bind_timelimit; ++ int ldap_version; ++ int bind_policy; ++ char *sslpath; ++ int ssl; ++ int referrals; ++ int restart; ++ int tls_checkpeer; ++ char *tls_cacertfile; ++ char *tls_cacertdir; ++ char *tls_ciphers; ++ char *tls_cert; ++ char *tls_key; ++ char *tls_randfile; ++ char *logdir; ++ int debug; ++ char *ssh_filter; ++} Options; ++ ++extern Options options; ++ ++void read_config_file(const char *); ++void initialize_options(void); ++void fill_default_options(void); ++void dump_config(void); ++ ++#endif /* LDAPCONF_H */ +diff -up openssh-5.6p1/ldap.conf.ldap openssh-5.6p1/ldap.conf +--- openssh-5.6p1/ldap.conf.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldap.conf 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,88 @@ ++# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $ ++# ++# This is the example configuration file for the OpenSSH ++# LDAP backend ++# ++# see ssh-ldap.conf(5) ++# ++ ++# URI with your LDAP server name. This allows to use ++# Unix Domain Sockets to connect to a local LDAP Server. ++#uri ldap://127.0.0.1/ ++#uri ldaps://127.0.0.1/ ++#uri ldapi://%2fvar%2frun%2fldapi_sock/ ++# Note: %2f encodes the '/' used as directory separator ++ ++# Another way to specify your LDAP server is to provide an ++# host name and the port of our LDAP server. Host name ++# must be resolvable without using LDAP. ++# Multiple hosts may be specified, each separated by a ++# space. How long nss_ldap takes to failover depends on ++# whether your LDAP client library supports configurable ++# network or connect timeouts (see bind_timelimit). ++#host 127.0.0.1 ++ ++# The port. ++# Optional: default is 389. ++#port 389 ++ ++# The distinguished name to bind to the server with. ++# Optional: default is to bind anonymously. ++#binddn cn=openssh_keys,dc=example,dc=org ++ ++# The credentials to bind with. ++# Optional: default is no credential. ++#bindpw TopSecret ++ ++# The distinguished name of the search base. ++#base dc=example,dc=org ++ ++# The LDAP version to use (defaults to 3 ++# if supported by client library) ++#ldap_version 3 ++ ++# The search scope. ++#scope sub ++#scope one ++#scope base ++ ++# Search timelimit ++#timelimit 30 ++ ++# Bind/connect timelimit ++#bind_timelimit 30 ++ ++# Reconnect policy: hard (default) will retry connecting to ++# the software with exponential backoff, soft will fail ++# immediately. ++#bind_policy hard ++ ++# SSL setup, may be implied by URI also. ++#ssl no ++#ssl on ++#ssl start_tls ++ ++# OpenLDAP SSL options ++# Require and verify server certificate (yes/no) ++# Default is to use libldap's default behavior, which can be configured in ++# /etc/openldap/ldap.conf using the TLS_REQCERT setting. The default for ++# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes". ++#tls_checkpeer hard ++ ++# CA certificates for server certificate verification ++# At least one of these are required if tls_checkpeer is "yes" ++#tls_cacertfile /etc/ssl/ca.cert ++#tls_cacertdir /etc/pki/tls/certs ++ ++# Seed the PRNG if /dev/urandom is not provided ++#tls_randfile /var/run/egd-pool ++ ++# SSL cipher suite ++# See man ciphers for syntax ++#tls_ciphers TLSv1 ++ ++# Client certificate and key ++# Use these, if your server requires client authentication. ++#tls_cert ++#tls_key ++ +diff -up openssh-5.6p1/ldap-helper.c.ldap openssh-5.6p1/ldap-helper.c +--- openssh-5.6p1/ldap-helper.c.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldap-helper.c 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,154 @@ ++/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "ldapincludes.h" ++#include "log.h" ++#include "misc.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include "ldapbody.h" ++#include ++#include ++ ++static int config_debug = 0; ++int config_exclusive_config_file = 0; ++static char *config_file_name = "/etc/ssh/ldap.conf"; ++static char *config_single_user = NULL; ++static int config_verbose = SYSLOG_LEVEL_VERBOSE; ++int config_warning_config_file = 0; ++extern char *__progname; ++ ++static void ++usage(void) ++{ ++ fprintf(stderr, "usage: %s [options]\n", ++ __progname); ++ fprintf(stderr, "Options:\n"); ++ fprintf(stderr, " -d Output the log messages to stderr.\n"); ++ fprintf(stderr, " -e Check the config file for unknown commands.\n"); ++ fprintf(stderr, " -f file Use alternate config file (default is /etc/ssh/ldap.conf).\n"); ++ fprintf(stderr, " -s user Do not demonize, send the user's key to stdout.\n"); ++ fprintf(stderr, " -v Increase verbosity of the debug output (implies -d).\n"); ++ fprintf(stderr, " -w Warn on unknown commands int the config file.\n"); ++ exit(1); ++} ++ ++/* ++ * Main program for the ssh pka ldap agent. ++ */ ++ ++int ++main(int ac, char **av) ++{ ++ int opt; ++ FILE *outfile = NULL; ++ ++ __progname = ssh_get_progname(av[0]); ++ ++ log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); ++ ++ /* ++ * Initialize option structure to indicate that no values have been ++ * set. ++ */ ++ initialize_options(); ++ ++ /* Parse command-line arguments. */ ++ while ((opt = getopt(ac, av, "def:s:vw")) != -1) { ++ switch (opt) { ++ case 'd': ++ config_debug = 1; ++ break; ++ ++ case 'e': ++ config_exclusive_config_file = 1; ++ config_warning_config_file = 1; ++ break; ++ ++ case 'f': ++ config_file_name = optarg; ++ break; ++ ++ case 's': ++ config_single_user = optarg; ++ outfile = fdopen (dup (fileno (stdout)), "w"); ++ break; ++ ++ case 'v': ++ config_debug = 1; ++ if (config_verbose < SYSLOG_LEVEL_DEBUG3) ++ config_verbose++; ++ break; ++ ++ case 'w': ++ config_warning_config_file = 1; ++ break; ++ ++ case '?': ++ default: ++ usage(); ++ break; ++ } ++ } ++ ++ /* Initialize loging */ ++ log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug); ++ ++ if (ac != optind) ++ fatal ("illegal extra parameter %s", av[1]); ++ ++ /* Ensure that fds 0 and 2 are open or directed to /dev/null */ ++ if (config_debug == 0) ++ sanitise_stdfd(); ++ ++ /* Read config file */ ++ read_config_file(config_file_name); ++ fill_default_options(); ++ if (config_verbose == SYSLOG_LEVEL_DEBUG3) { ++ debug3 ("=== Configuration ==="); ++ dump_config(); ++ debug3 ("=== *** ==="); ++ } ++ ++ ldap_checkconfig(); ++ ldap_do_connect(); ++ ++ if (config_single_user) { ++ process_user (config_single_user, outfile); ++ } else { ++ fatal ("Not yet implemented"); ++/* TODO ++ * open unix socket a run the loop on it ++ */ ++ } ++ ++ ldap_do_close(); ++ return 0; ++} ++ ++/* Ugly hack */ ++void *buffer_get_string(Buffer *b, u_int *l) {} ++void buffer_put_string(Buffer *b, const void *f, u_int l) {} ++ +diff -up openssh-5.6p1/ldap-helper.h.ldap openssh-5.6p1/ldap-helper.h +--- openssh-5.6p1/ldap-helper.h.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldap-helper.h 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LDAP_HELPER_H ++#define LDAP_HELPER_H ++ ++extern int config_exclusive_config_file; ++extern int config_warning_config_file; ++ ++#endif /* LDAP_HELPER_H */ +diff -up openssh-5.6p1/ldapincludes.h.ldap openssh-5.6p1/ldapincludes.h +--- openssh-5.6p1/ldapincludes.h.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapincludes.h 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,41 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LDAPINCLUDES_H ++#define LDAPINCLUDES_H ++ ++#include "includes.h" ++ ++#ifdef HAVE_LBER_H ++#include ++#endif ++#ifdef HAVE_LDAP_H ++#include ++#endif ++#ifdef HAVE_LDAP_SSL_H ++#include ++#endif ++ ++#endif /* LDAPINCLUDES_H */ +diff -up openssh-5.6p1/ldapmisc.c.ldap openssh-5.6p1/ldapmisc.c +--- openssh-5.6p1/ldapmisc.c.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapmisc.c 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,79 @@ ++ ++#include "ldapincludes.h" ++#include "ldapmisc.h" ++ ++#ifndef HAVE_LDAP_GET_LDERRNO ++int ++ldap_get_lderrno (LDAP * ld, char **m, char **s) ++{ ++#ifdef HAVE_LDAP_GET_OPTION ++ int rc; ++#endif ++ int lderrno; ++ ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) ++ return rc; ++#else ++ lderrno = ld->ld_errno; ++#endif ++ ++ if (s != NULL) { ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) ++ return rc; ++#else ++ *s = ld->ld_error; ++#endif ++ } ++ ++ if (m != NULL) { ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) ++ return rc; ++#else ++ *m = ld->ld_matched; ++#endif ++ } ++ ++ return lderrno; ++} ++#endif ++ ++#ifndef HAVE_LDAP_SET_LDERRNO ++int ++ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s) ++{ ++#ifdef HAVE_LDAP_SET_OPTION ++ int rc; ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_errno = lderrno; ++#endif ++ ++ if (s != NULL) { ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_error = s; ++#endif ++ } ++ ++ if (m != NULL) { ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_matched = m; ++#endif ++ } ++ ++ return LDAP_SUCCESS; ++} ++#endif ++ +diff -up openssh-5.6p1/ldapmisc.h.ldap openssh-5.6p1/ldapmisc.h +--- openssh-5.6p1/ldapmisc.h.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ldapmisc.h 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,35 @@ ++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LDAPMISC_H ++#define LDAPMISC_H ++ ++#include "ldapincludes.h" ++ ++int ldap_get_lderrno (LDAP *, char **, char **); ++int ldap_set_lderrno (LDAP *, int, const char *, const char *); ++ ++#endif /* LDAPMISC_H */ ++ +diff -up openssh-5.6p1/lpk-user-example.txt.ldap openssh-5.6p1/lpk-user-example.txt +--- openssh-5.6p1/lpk-user-example.txt.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/lpk-user-example.txt 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,117 @@ ++ ++Post to ML -> User Made Quick Install Doc. ++Contribution from John Lane ++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++OpenSSH LDAP keystore Patch ++=========================== ++ ++NOTE: these notes are a transcript of a specific installation ++ they work for me, your specifics may be different! ++ from John Lane March 17th 2005 john@lane.uk.net ++ ++This is a patch to OpenSSH 4.0p1 to allow it to obtain users' public keys ++from their LDAP record as an alternative to ~/.ssh/authorized_keys. ++ ++(Assuming here that necessary build stuff is in $BUILD) ++ ++cd $BUILD/openssh-4.0p1 ++patch -Np1 -i $BUILD/openssh-lpk-4.0p1-0.3.patch ++mkdir -p /var/empty && ++./configure --prefix=/usr --sysconfdir=/etc/ssh \ ++ --libexecdir=/usr/sbin --with-md5-passwords --with-pam \ ++ --with-libs="-lldap" --with-cppflags="-DWITH_LDAP_PUBKEY" ++Now do. ++make && ++make install ++ ++Add the following config to /etc/ssh/ssh_config ++UseLPK yes ++LpkServers ldap://myhost.mydomain.com ++LpkUserDN ou=People,dc=mydomain,dc=com ++ ++We need to tell sshd about the SSL keys during boot, as root's ++environment does not exist at that time. Edit /etc/rc.d/init.d/sshd. ++Change the startup code from this: ++ echo "Starting SSH Server..." ++ loadproc /usr/sbin/sshd ++ ;; ++to this: ++ echo "Starting SSH Server..." ++ LDAPRC="/root/.ldaprc" loadproc /usr/sbin/sshd ++ ;; ++ ++Re-start the sshd daemon: ++/etc/rc.d/init.d/sshd restart ++ ++Install the additional LDAP schema ++cp $BUILD/openssh-lpk-0.2.schema /etc/openldap/schema/openssh.schema ++ ++Now add the openSSH LDAP schema to /etc/openldap/slapd.conf: ++Add the following to the end of the existing block of schema includes ++include /etc/openldap/schema/openssh.schema ++ ++Re-start the LDAP server: ++/etc/rc.d/init.d/slapd restart ++ ++To add one or more public keys to a user, eg "testuser" : ++ldapsearch -x -W -Z -LLL -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D ++"uid=testuser,ou=People,dc=mydomain,dc=com" > /tmp/testuser ++ ++append the following to this /tmp/testuser file ++objectclass: ldapPublicKey ++sshPublicKey: ssh-rsa ++AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KS ++qIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z8XwSsuAoR1t86t+5dlI ++7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key ++ ++Then do a modify: ++ldapmodify -x -D "uid=testuser,ou=People,dc=mydomain,dc=com" -W -f ++/tmp/testuser -Z ++Enter LDAP Password: ++modifying entry "uid=testuser,ou=People,dc=mydomain,dc=com" ++And check the modify is ok: ++ldapsearch -x -W -Z -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D ++"uid=testuser,ou=People,dc=mydomain,dc=com" ++Enter LDAP Password: ++# extended LDIF ++# ++# LDAPv3 ++# base with scope sub ++# filter: (objectclass=*) ++# requesting: ALL ++# ++ ++# testuser, People, mydomain.com ++dn: uid=testuser,ou=People,dc=mydomain,dc=com ++uid: testuser ++cn: testuser ++objectClass: account ++objectClass: posixAccount ++objectClass: top ++objectClass: shadowAccount ++objectClass: ldapPublicKey ++shadowLastChange: 12757 ++shadowMax: 99999 ++shadowWarning: 7 ++loginShell: /bin/bash ++uidNumber: 9999 ++gidNumber: 501 ++homeDirectory: /home/testuser ++userPassword:: e1NTSEF9UDgwV1hnM1VjUDRJK0k1YnFiL1d4ZUJObXlZZ3Z3UTU= ++sshPublicKey: ssh-rsa ++AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KSqIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z ++8XwSsuAoR1t86t+5dlI7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key ++ ++# search result ++search: 3 ++result: 0 Success ++ ++# numResponses: 2 ++# numEntries: 1 ++ ++Now start a ssh session to user "testuser" from usual ssh client (e.g. ++puTTY). Login should succeed. ++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +diff -up openssh-5.6p1/Makefile.in.ldap openssh-5.6p1/Makefile.in +--- openssh-5.6p1/Makefile.in.ldap 2010-05-12 08:51:39.000000000 +0200 ++++ openssh-5.6p1/Makefile.in 2010-08-23 12:29:24.000000000 +0200 +@@ -26,6 +26,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpas + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper ++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper + RAND_HELPER=$(libexecdir)/ssh-rand-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +@@ -61,8 +62,9 @@ EXEEXT=@EXEEXT@ + + INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ + INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ ++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ + +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) + + LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ + canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ +@@ -93,8 +95,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ + roaming_common.o roaming_serv.o + +-MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out +-MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ++MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out ++MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5 + MANTYPE = @MANTYPE@ + + CONFIGFILES=sshd_config.out ssh_config.out moduli.out +@@ -162,6 +164,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss + ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o + $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + ++ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o ++ $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) ++ + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o + $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + +@@ -266,6 +271,9 @@ install-files: + fi + $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ $(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ ++ fi + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 +@@ -285,6 +293,10 @@ install-files: + $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 + $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 + $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ $(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \ ++ $(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \ ++ fi + -rm -f $(DESTDIR)$(bindir)/slogin + ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 +@@ -321,6 +333,13 @@ install-sysconf: + else \ + echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ + fi ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \ ++ $(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \ ++ else \ ++ echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \ ++ fi ; \ ++ fi + + host-key: ssh-keygen$(EXEEXT) + @if [ -z "$(DESTDIR)" ] ; then \ +@@ -384,6 +403,7 @@ uninstall: + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 ++ -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 + + tests interop-tests: $(TARGETS) +diff -up openssh-5.6p1/openssh-lpk-openldap.schema.ldap openssh-5.6p1/openssh-lpk-openldap.schema +--- openssh-5.6p1/openssh-lpk-openldap.schema.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/openssh-lpk-openldap.schema 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,21 @@ ++# ++# LDAP Public Key Patch schema for use with openssh-ldappubkey ++# useful with PKA-LDAP also ++# ++# Author: Eric AUGE ++# ++# Based on the proposal of : Mark Ruijter ++# ++ ++ ++# octetString SYNTAX ++attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' ++ DESC 'MANDATORY: OpenSSH Public key' ++ EQUALITY octetStringMatch ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) ++ ++# printableString SYNTAX yes|no ++objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY ++ DESC 'MANDATORY: OpenSSH LPK objectclass' ++ MUST ( sshPublicKey $ uid ) ++ ) +diff -up openssh-5.6p1/openssh-lpk-sun.schema.ldap openssh-5.6p1/openssh-lpk-sun.schema +--- openssh-5.6p1/openssh-lpk-sun.schema.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/openssh-lpk-sun.schema 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,23 @@ ++# ++# LDAP Public Key Patch schema for use with openssh-ldappubkey ++# useful with PKA-LDAP also ++# ++# Author: Eric AUGE ++# ++# Schema for Sun Directory Server. ++# Based on the original schema, modified by Stefan Fischer. ++# ++ ++dn: cn=schema ++ ++# octetString SYNTAX ++attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' ++ DESC 'MANDATORY: OpenSSH Public key' ++ EQUALITY octetStringMatch ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) ++ ++# printableString SYNTAX yes|no ++objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY ++ DESC 'MANDATORY: OpenSSH LPK objectclass' ++ MUST ( sshPublicKey $ uid ) ++ ) +diff -up openssh-5.6p1/README.lpk.ldap openssh-5.6p1/README.lpk +--- openssh-5.6p1/README.lpk.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/README.lpk 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,274 @@ ++OpenSSH LDAP PUBLIC KEY PATCH ++Copyright (c) 2003 Eric AUGE (eau@phear.org) ++All rights reserved. ++ ++Rewriten by Jan F.�Chadima (jchadima@redhat.com) ++Copyright (c) 2010 Red Hat, Inc. ++The new PKA-LDAP patch is rewritten from the scratch. ++LDAP schema and part of the documentation is based on original ++LPK project (http://code.google.com/p/openssh-lpk), ++copyright (c) 2003 Eric AUGE ++The new openssh configuration is different from the original LPK one. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions ++are met: ++1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++3. The name of the author may not be used to endorse or promote products ++ derived from this software without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++purposes of this patch: ++ ++This patch would help to have authentication centralization policy ++using ssh public key authentication. ++This patch could be an alternative to other "secure" authentication system ++working in a similar way (Kerberos, SecurID, etc...), except the fact ++that it's based on OpenSSH and its public key abilities. ++ ++>> FYI: << ++'uid': means unix accounts existing on the current server ++'ServerGroup:' mean server group configured on the current server by the SSH_Filter option in the ldap.conf. ++ ++example schema: ++ ++ ++ server1 (uid: eau,rival,toto) (ServerGroup: unix) ++ ___________ / ++ / \ --- - server3 (uid: eau, titi) (ServerGroup: unix) ++ | LDAP Server | \ ++ | eau ,rival | server2 (uid: rival, eau) (ServerGroup: unix) ++ | titi ,toto | ++ | userx,.... | server5 (uid: eau) (ServerGroup: mail) ++ \___________/ \ / ++ ----- - server4 (uid: eau, rival) (no group configured) ++ \ ++ etc... ++ ++- WHAT WE NEED : ++ ++ * configured LDAP server somewhere on the network (i.e. OpenLDAP) ++ * patched sshd (with this patch ;) ++ * LDAP user(/group) entry (look at users.ldif (& groups.ldif)): ++ User entry: ++ - attached to the 'ldapPublicKey' objectclass ++ - attached to the 'posixAccount' objectclass ++ - with a filled 'sshPublicKey' attribute ++ Example: ++ dn: uid=eau,ou=users,dc=cuckoos,dc=net ++ objectclass: top ++ objectclass: person ++ objectclass: organizationalPerson ++ objectclass: posixAccount ++ objectclass: ldapPublicKey ++ description: Eric AUGE Account ++ userPassword: blah ++ cn: Eric AUGE ++ sn: Eric AUGE ++ uid: eau ++ uidNumber: 1034 ++ gidNumber: 1 ++ homeDirectory: /export/home/eau ++ sshPublicKey: ssh-dss AAAAB3... ++ sshPublicKey: ssh-dss AAAAM5... ++ ++ Group entry: ++ - attached to the 'posixGroup' objectclass ++ - with a 'cn' groupname attribute ++ - with multiple 'memberUid' attributes filled with usernames allowed in this group ++ Example: ++ # few members ++ dn: cn=unix,ou=groups,dc=cuckoos,dc=net ++ objectclass: top ++ objectclass: posixGroup ++ description: Unix based servers group ++ cn: unix ++ gidNumber: 1002 ++ memberUid: eau ++ memberUid: user1 ++ memberUid: user2 ++ ++ ++- HOW IT WORKS : ++ ++ * without patch ++ If a user wants to authenticate to log in a server the sshd, will first look for authentication method allowed (RSAauth,kerberos,etc..) ++ and if RSAauth and tickets based auth fails, it will fallback to standard password authentication (if enabled). ++ ++ * with the patch ++ If a user want to authenticate to log in a server, the sshd will first look for auth method including LDAP pubkey, if the ldappubkey options is enabled. ++ It will do an ldapsearch to get the public key directly from the LDAP instead of reading it from the server filesystem. ++ (usually in $HOME/.ssh/authorized_keys) ++ ++ 2 tokens are added to sshd_config : ++ # here is the new patched ldap related tokens ++ AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-helper -s %u ++ AuthorizedKeysCommandRunAs nobody ++ ++ The LDAP configuratin is read from common /etc/ldap.conf configuration file. ++There is also one optional parameter in the LDAP configuration file, SSH_Filter, which is a LDAP filter limiting keys to be searched. ++ ++- HOW TO INSERT A USER/KEY INTO AN LDAP ENTRY ++ ++ * my way (there is plenty :) ++ - create ldif file (i.e. users.ldif) ++ - cat ~/.ssh/id_dsa.pub OR cat ~/.ssh/id_rsa.pub OR cat ~/.ssh/identity.pub ++ - my way in 4 steps : ++ Example: ++ ++ # you add this to the user entry in the LDIF file : ++ [...] ++ objectclass: posixAccount ++ objectclass: ldapPublicKey ++ [...] ++ sshPubliKey: ssh-dss AAAABDh12DDUR2... ++ [...] ++ ++ # insert your entry and you're done :) ++ ldapadd -D balblabla -w bleh < file.ldif ++ ++ all standard options can be present in the 'sshPublicKey' attribute. ++ ++- WHY : ++ ++ Simply because, i was looking for a way to centralize all sysadmins authentication, easily, without completely using LDAP ++ as authentication method (like pam_ldap etc..). ++ ++ After looking into Kerberos, SecurID, and other centralized secure authentications systems, the use of RSA and LDAP to get ++ public key for authentication allows us to control who has access to which server (the user needs an account and to be in 'strongAuthenticationUser' ++ objectclass within LDAP and part of the group the SSH server is in). ++ ++ Passwords update are no longer a nightmare for a server farm (key pair passphrase is stored on each user's box and private key is locally encrypted using his passphrase ++ so each user can change it as much as he wants). ++ ++ Blocking a user account can be done directly from the LDAP (if sshd is using RSAAuth + ldap only). ++ ++- RULES : ++ Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema. ++ and the additionnal lpk.schema. ++ ++ This patch could allow a smooth transition between standard auth (/etc/passwd) and complete LDAP based authentication ++ (pamldap, nss_ldap, etc..). ++ ++ This can be an alternative to other (old?/expensive?) authentication methods (Kerberos/SecurID/..). ++ ++ Referring to schema at the beginning of this file if user 'eau' is only in group 'unix' ++ 'eau' would ONLY access 'server1', 'server2', 'server3' AND 'server4' BUT NOT 'server5'. ++ If you then modify the LDAP 'mail' group entry to add 'memberUid: eau' THEN user 'eau' would be able ++ to log in 'server5' (i hope you got the idea, my english is bad :). ++ ++ Each server's sshd is patched and configured to ask the public key and the group infos in the LDAP ++ server. ++ When you want to allow a new user to have access to the server parc, you just add him an account on ++ your servers, you add his public key into his entry on the LDAP server, it's done. ++ ++ Because sshds are looking public keys into the LDAP directly instead of a file ($HOME/.ssh/authorized_keys). ++ ++ When the user needs to change his passphrase he can do it directly from his workstation by changing ++ his own key set lock passphrase, and all servers are automatically aware. ++ ++ With a CAREFUL LDAP server configuration you could allow a user to add/delete/modify his own entry himself ++ so he can add/modify/delete himself his public key when needed. ++ ++� FLAWS : ++ LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP ++ allow write to users dn, somebody could replace someuser's public key by its own and impersonate some ++ of your users in all your server farm be VERY CAREFUL. ++ ++ MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login ++ as the impersonnated user. ++ ++ If LDAP server is down then, no fallback on passwd auth. ++ ++ the ldap code part has not been well audited yet. ++ ++- LDAP USER ENTRY EXAMPLES (LDIF Format, look in users.ldif) ++ --- CUT HERE --- ++ dn: uid=jdoe,ou=users,dc=foobar,dc=net ++ objectclass: top ++ objectclass: person ++ objectclass: organizationalPerson ++ objectclass: posixAccount ++ objectclass: ldapPublicKey ++ description: My account ++ cn: John Doe ++ sn: John Doe ++ uid: jdoe ++ uidNumber: 100 ++ gidNumber: 100 ++ homeDirectory: /home/jdoe ++ sshPublicKey: ssh-dss AAAAB3NzaC1kc3MAAAEBAOvL8pREUg9wSy/8+hQJ54YF3AXkB0OZrXB.... ++ [...] ++ --- CUT HERE --- ++ ++- LDAP GROUP ENTRY EXAMPLES (LDIF Format, look in groups.ldif) ++ --- CUT HERE --- ++ dn: cn=unix,ou=groups,dc=cuckoos,dc=net ++ objectclass: top ++ objectclass: posixGroup ++ description: Unix based servers group ++ cn: unix ++ gidNumber: 1002 ++ memberUid: jdoe ++ memberUid: user1 ++ memberUid: user2 ++ [...] ++ --- CUT HERE --- ++ ++>> FYI: << ++Multiple 'sshPublicKey' in a user entry are allowed, as well as multiple 'memberUid' attributes in a group entry ++ ++- COMPILING: ++ 1. Apply the patch ++ 2. ./configure --with-your-options --with-ldap=/prefix/to/ldap_libs_and_includes ++ 3. make ++ 4. it's done. ++ ++- BLA : ++ I hope this could help, and i hope to be clear enough,, or give ideas. questions/comments/improvements are welcome. ++ ++- TODO : ++ Possibility to reuse the ssh-ldap-helper. ++ Tune the LDAP part to all possible LDAP configurations. ++ ++- DIFFERENCES FROM ORIGINAL lpk ++ No LDAP code in sshd. ++ Support for various LDAP platforms and configurations. ++ LDAP is configured in separate ldap.conf file. ++ ++- DOCS/LINK : ++ http://pacsec.jp/core05/psj05-barisani-en.pdf ++ http://fritz.potsdam.edu/projects/openssh-lpk/ ++ http://fritz.potsdam.edu/projects/sshgate/ ++ http://dev.inversepath.com/trac/openssh-lpk ++ http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm ) ++ ++- CONTRIBUTORS/IDEAS/GREETS : ++ - Eric AUGE ++ - Andrea Barisani ++ - Falk Siemonsmeier. ++ - Jacob Rief. ++ - Michael Durchgraf. ++ - frederic peters. ++ - Finlay dobbie. ++ - Stefan Fisher. ++ - Robin H. Johnson. ++ - Adrian Bridgett. ++ ++- CONTACT : ++ Jan F. Chadima ++ +diff -up openssh-5.6p1/ssh-ldap.conf.5.ldap openssh-5.6p1/ssh-ldap.conf.5 +--- openssh-5.6p1/ssh-ldap.conf.5.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ssh-ldap.conf.5 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,373 @@ ++.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $ ++.\" ++.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. ++.\" ++.\" Permission to use, copy, modify, and distribute this software for any ++.\" purpose with or without fee is hereby granted, provided that the above ++.\" copyright notice and this permission notice appear in all copies. ++.\" ++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++.\" ++.Dd $Mdocdate: may 12 2010 $ ++.Dt SSH-LDAP.CONF 5 ++.Os ++.Sh NAME ++.Nm ssh-ldap.conf ++.Nd configuration file for ssh-ldap-helper ++.Sh SYNOPSIS ++.Nm /etc/ssh/ldap.conf ++.Sh DESCRIPTION ++.Xr ssh-ldap-helper 8 ++reads configuration data from ++.Pa /etc/ssh/ldap.conf ++(or the file specified with ++.Fl f ++on the command line). ++The file contains keyword-argument pairs, one per line. ++Lines starting with ++.Ql # ++and empty lines are interpreted as comments. ++.Pp ++The value starts with the first non-blank character after ++the keyword's name, and terminates at the end of the line, ++or at the last sequence of blanks before the end of the line. ++Quoting values that contain blanks ++may be incorrect, as the quotes would become part of the value. ++The possible keywords and their meanings are as follows (note that ++keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive). ++.It Cm URI ++The argument(s) are in the form ++.Pa ldap[si]://[name[:port]] ++and specify the URI(s) of an LDAP server(s) to which the ++.Xr ssh-ldap-helper 8 ++should connect. The URI scheme may be any of ++.Dq ldap , ++.Dq ldaps ++or ++.Dq ldapi , ++which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP ++over IPC (UNIX domain sockets), respectively. ++Each server's name can be specified as a ++domain-style name or an IP address literal. Optionally, the ++server's name can followed by a ':' and the port number the LDAP ++server is listening on. If no port number is provided, the default ++port for the scheme is used (389 for ldap://, 636 for ldaps://). ++For LDAP over IPC, name is the name of the socket, and no port ++is required, nor allowed; note that directory separators must be ++URL-encoded, like any other characters that are special to URLs; ++A space separated list of URIs may be provided. ++There is no default. ++.It Cm Base ++Specifies the default base Distinguished Name (DN) to use when performing ldap operations. ++The base must be specified as a DN in LDAP format. ++There is no default. ++.It Cm BindDN ++Specifies the default BIND DN to use when connecting to the ldap server. ++The bind DN must be specified as a Distinguished Name in LDAP format. ++There is no default. ++.It Cm BindPW ++Specifies the default password to use when connecting to the ldap server via ++.Cm BindDN . ++There is no default. ++.It Cm RootBindDN ++Intentionaly does nothing. Recognized for compatibility reasons. ++.It Cm Host ++The argument(s) specifies the name(s) of an LDAP server(s) to which the ++.Xr ssh-ldap-helper 8 ++should connect. Each server's name can be specified as a ++domain-style name or an IP address and optionally followed by a ':' and ++the port number the ldap server is listening on. A space-separated ++list of hosts may be provided. ++There is no default. ++.Cm Host ++is deprecated in favor of ++.Cm URI . ++.It Cm Port ++Specifies the default port used when connecting to LDAP servers(s). ++The port may be specified as a number. ++The default port is 389 for ldap:// or 636 for ldaps:// respectively. ++.Cm Port ++is deprecated in favor of ++.Cm URI . ++.It Cm Scope ++Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend. ++There are three options (values) that can be assigned to the ++.Cm Scope parameter: ++.Dq base , ++.Dq one ++and ++.Dq subtree . ++Alias for the subtree is ++.Dq sub . ++The value ++.Dq base ++is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!). ++The value ++.Dq one ++is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN. ++The value ++.Dq subtree ++is used to indicate searching of all entries at all levels under and including the specified base DN. ++The default is ++.Dq subtree . ++.It Cm Deref ++Specifies how alias dereferencing is done when performing a search. There are four ++possible values that can be assigned to the ++.Cm Deref ++parameter: ++.Dq never , ++.Dq searching , ++.Dq finding , ++and ++.Dq always . ++The value ++.Dq never ++means that the aliases are never dereferenced. ++The value ++.Dq searching ++means that the aliases are dereferenced in subordinates of the base object, but ++not in locating the base object of the search. ++The value ++.Dq finding ++means that the aliases are only dereferenced when locating the base object of the search. ++The value ++.Dq always ++means that the aliases are dereferenced both in searching and in locating the base object ++of the search. ++The default is ++.Dq never . ++.It Cm TimeLimit ++Specifies a time limit (in seconds) to use when performing searches. ++The number should be a non-negative integer. A ++.Cm TimeLimit ++of zero (0) specifies that the search time is unlimited. Please note that the server ++may still apply any server-side limit on the duration of a search operation. ++The default value is 10. ++.It Cm TimeOut ++Is an aliast to ++.Cm TimeLimit . ++.It Cm Bind_TimeLimit ++Specifies the timeout (in seconds) after which the poll(2)/select(2) ++following a connect(2) returns in case of no activity. ++The default value is 10. ++.It Cm Network_TimeOut ++Is an alias to ++.Cm Bind_TimeLimit . ++.It Cm Ldap_Version ++Specifies what version of the LDAP protocol should be used. ++The allowed values are 2 or 3. The default is 3. ++.It Cm Version ++Is an alias to ++.Cm Ldap_Version . ++.It Cm Bind_Policy ++Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values: ++.Dq hard ++and ++.Dq soft. ++.Dq hard has 2 aliases ++.Dq hard_open ++and ++.Dq hard_init . ++The value ++.Dq hard ++means that reconects that the ++.Xr ssh-ldap-helper 8 ++tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying. ++The value ++.Dq soft ++means that ++.Xr ssh-ldap-helper 8 ++fails immediately when it cannot connect to the LDAP seerver. ++The deault is ++.Dq hard . ++.It Cm SSLPath ++Specifies the path to the X.509 certificate database. ++There is no default. ++.It Cm SSL ++Specifies whether to use SSL/TLS or not. ++There are three allowed values: ++.Dq yes , ++.Dq no ++and ++.Dq start_tls ++Both ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++If ++.Dqstart_tls ++is specified then StartTLS is used rather than raw LDAP over SSL. ++The default for ldap:// is ++.Dq start_tls , ++for ldaps:// ++.Dq yes ++and ++.Dq no ++for the ldapi:// . ++In case of host based configuration the default is ++.Dq start_tls . ++.It Cm Referrals ++Specifies if the client should automatically follow referrals returned ++by LDAP servers. ++The value can be or ++.Dq yes ++or ++.Dq no . ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++The default is yes. ++.It Cm Restart ++Specifies whether the LDAP client library should restart the select(2) system call when interrupted. ++The value can be or ++.Dq yes ++or ++.Dq no . ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++The default is yes. ++.It Cm TLS_CheckPeer ++Specifies what checks to perform on server certificates in a TLS session, ++if any. The value ++can be specified as one of the following keywords: ++.Dq never , ++.Dq hard , ++.Dq demand , ++.Dq allow ++and ++.Dq try . ++.Dq true , ++.Dq on ++and ++.Dq yes ++are aliases for ++.Dq hard . ++.Dq false , ++.Dq off ++and ++.Dq no ++are the aliases for ++.Dq never . ++The value ++.Dq never ++means that the client will not request or check any server certificate. ++The value ++.Dq allow ++means that the server certificate is requested. If no certificate is provided, ++the session proceeds normally. If a bad certificate is provided, it will ++be ignored and the session proceeds normally. ++The value ++.Dq try ++means that the server certificate is requested. If no certificate is provided, ++the session proceeds normally. If a bad certificate is provided, ++the session is immediately terminated. ++The value ++.Dq demand ++means that the server certificate is requested. If no ++certificate is provided, or a bad certificate is provided, the session ++is immediately terminated. ++The value ++.Dq hard ++is the same as ++.Dq demand . ++It requires an SSL connection. In the case of the plain conection the ++session is immediately terminated. ++The default is ++.Dq hard . ++.It Cm TLS_ReqCert ++Is an alias for ++.Cm TLS_CheckPeer . ++.It Cm TLS_CACertFile ++Specifies the file that contains certificates for all of the Certificate ++Authorities the client will recognize. ++There is no default. ++.It Cm TLS_CACert ++Is an alias for ++.Cm TLS_CACertFile . ++.It Cm TLS_CACertDIR ++Specifies the path of a directory that contains Certificate Authority ++certificates in separate individual files. The ++.Cm TLS_CACert ++is always used before ++.Cm TLS_CACertDir . ++The specified directory must be managed with the OpenSSL c_rehash utility. ++There is no default. ++.It Cm TLS_Ciphers ++Specifies acceptable cipher suite and preference order. ++The value should be a cipher specification for OpenSSL, ++e.g., ++.Dq HIGH:MEDIUM:+SSLv2 . ++The default is ++.Dq ALL . ++.It Cm TLS_Cipher_Suite ++Is an alias for ++.Cm TLS_Ciphers . ++.It Cm TLS_Cert ++Specifies the file that contains the client certificate. ++There is no default. ++.It Cm TLS_Certificate ++Is an alias for ++.Cm TLS_Cert . ++.It Cm TLS_Key ++Specifies the file that contains the private key that matches the certificate ++stored in the ++.Cm TLS_Cert ++file. Currently, the private key must not be protected with a password, so ++it is of critical importance that the key file is protected carefully. ++There is no default. ++.It Cm TLS_RandFile ++Specifies the file to obtain random bits from when /dev/[u]random is ++not available. Generally set to the name of the EGD/PRNGD socket. ++The environment variable RANDFILE can also be used to specify the filename. ++There is no default. ++.It Cm LogDir ++Specifies the directory used for logging by the LDAP client library. ++There is no default. ++.It Cm Debug ++Specifies the debug level used for logging by the LDAP client library. ++There is no default. ++.It Cm SSH_Filter ++Specifies the user filter applied on the LDAP serch. ++The default is no filter. ++.Sh FILES ++.Bl -tag -width Ds ++.It Pa /etc/ssh/ldap.conf ++Ldap configuration file for ++.Xr ssh-ldap-helper 8 . ++.Sh "SEE ALSO" ++.Xr ldap.conf 5 , ++.Xr ssh-ldap-helper 8 ++.Sh HISTORY ++.Nm ++first appeared in ++OpenSSH 5.5 + PKA-LDAP . ++.Sh AUTHORS ++.An Jan F. Chadima Aq jchadima@redhat.com +diff -up openssh-5.6p1/ssh-ldap-helper.8.ldap openssh-5.6p1/ssh-ldap-helper.8 +--- openssh-5.6p1/ssh-ldap-helper.8.ldap 2010-08-23 12:28:11.000000000 +0200 ++++ openssh-5.6p1/ssh-ldap-helper.8 2010-08-23 12:28:11.000000000 +0200 +@@ -0,0 +1,78 @@ ++.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ ++.\" ++.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. ++.\" ++.\" Permission to use, copy, modify, and distribute this software for any ++.\" purpose with or without fee is hereby granted, provided that the above ++.\" copyright notice and this permission notice appear in all copies. ++.\" ++.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++.\" ++.Dd $Mdocdate: April 29 2010 $ ++.Dt SSH-LDAP-HELPER 8 ++.Os ++.Sh NAME ++.Nm ssh-ldap-helper ++.Nd sshd helper program for ldap support ++.Sh SYNOPSIS ++.Nm ssh-ldap-helper ++.Op Fl devw ++.Op Fl f Ar file ++.Op Fl s Ar user ++.Sh DESCRIPTION ++.Nm ++is used by ++.Xr sshd 1 ++to access keys provided by an LDAP. ++.Nm ++is disabled by default and can only be enabled in the ++sshd configuration file ++.Pa /etc/ssh/sshd_config ++by setting ++.Cm AuthorizedKeysCommand ++to ++.Dq /usr/libexec/ssh-ldap-helper -s %u . ++.Pp ++.Nm ++is not intended to be invoked by the user, but from ++.Xr sshd 8 . ++.Pp ++The options are as follows: ++.Bl -tag -width Ds ++.It Fl d ++Set the debug mode; ++.Nm ++prints all logs to stderr instead of syslog. ++.It Fl e ++Implies \-w; ++.Nm ++halts if it encounters an unknown item in the ldap.conf file. ++.It Fl f ++.Nm ++uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default). ++.It Fl s ++.Nm ++prints out the user's keys to stdout and exits. ++.It Fl v ++Implies \-d; ++increases verbosity. ++.It Fl w ++.Nm ++writes warnings about unknown items in the ldap.conf configuration file. ++ ++.Sh SEE ALSO ++.Xr sshd 8 , ++.Xr sshd_config 5 , ++.Xr ssh-ldap.conf 5 , ++.Sh HISTORY ++.Nm ++first appeared in ++OpenSSH 5.5 + PKA-LDAP . ++.Sh AUTHORS ++.An Jan F. Chadima Aq jchadima@redhat.com diff --git a/openssh-5.6p1-mls.patch b/openssh-5.6p1-mls.patch new file mode 100644 index 0000000..ee8a8ef --- /dev/null +++ b/openssh-5.6p1-mls.patch @@ -0,0 +1,430 @@ +diff -up openssh-5.6p1/configure.ac.mls openssh-5.6p1/configure.ac +--- openssh-5.6p1/configure.ac.mls 2010-08-23 12:11:36.000000000 +0200 ++++ openssh-5.6p1/configure.ac 2010-08-23 12:11:36.000000000 +0200 +@@ -3390,6 +3390,7 @@ AC_ARG_WITH(selinux, + SSHDLIBS="$SSHDLIBS $LIBSELINUX" + LIBS="$LIBS $LIBSELINUX" + AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level) ++ AC_CHECK_FUNCS(setkeycreatecon) + LIBS="$save_LIBS" + fi ] + ) +diff -up openssh-5.6p1/misc.c.mls openssh-5.6p1/misc.c +--- openssh-5.6p1/misc.c.mls 2010-08-03 08:05:05.000000000 +0200 ++++ openssh-5.6p1/misc.c 2010-08-23 12:14:16.000000000 +0200 +@@ -424,6 +424,7 @@ char * + colon(char *cp) + { + int flag = 0; ++ int start = 1; + + if (*cp == ':') /* Leading colon is part of file name. */ + return NULL; +@@ -439,6 +440,13 @@ colon(char *cp) + return (cp); + if (*cp == '/') + return NULL; ++ if (start) { ++ /* Slash on beginning or after dots only denotes file name. */ ++ if (*cp == '/') ++ return (0); ++ if (*cp != '.') ++ start = 0; ++ } + } + return NULL; + } +diff -up openssh-5.6p1/openbsd-compat/port-linux.c.mls openssh-5.6p1/openbsd-compat/port-linux.c +--- openssh-5.6p1/openbsd-compat/port-linux.c.mls 2010-08-23 12:11:36.000000000 +0200 ++++ openssh-5.6p1/openbsd-compat/port-linux.c 2010-08-23 12:11:37.000000000 +0200 +@@ -35,13 +35,24 @@ + #include "key.h" + #include "hostfile.h" + #include "auth.h" ++#include "xmalloc.h" + + #ifdef WITH_SELINUX + #include + #include ++#include + #include ++#include ++#include ++ ++#ifdef HAVE_LINUX_AUDIT ++#include ++#include ++#endif + + extern Authctxt *the_authctxt; ++extern int inetd_flag; ++extern int rexeced_flag; + + /* Wrapper around is_selinux_enabled() to log its return value once only */ + int +@@ -57,17 +68,173 @@ ssh_selinux_enabled(void) + return (enabled); + } + ++/* Send audit message */ ++static int ++send_audit_message(int success, security_context_t default_context, ++ security_context_t selected_context) ++{ ++ int rc=0; ++#ifdef HAVE_LINUX_AUDIT ++ char *msg = NULL; ++ int audit_fd = audit_open(); ++ security_context_t default_raw=NULL; ++ security_context_t selected_raw=NULL; ++ rc = -1; ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return 0; /* No audit support in kernel */ ++ error("Error connecting to audit system."); ++ return rc; ++ } ++ if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) { ++ error("Error translating default context."); ++ default_raw = NULL; ++ } ++ if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) { ++ error("Error translating selected context."); ++ selected_raw = NULL; ++ } ++ if (asprintf(&msg, "sshd: default-context=%s selected-context=%s", ++ default_raw ? default_raw : (default_context ? default_context: "?"), ++ selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) { ++ error("Error allocating memory."); ++ goto out; ++ } ++ if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE, ++ msg, NULL, NULL, NULL, success) <= 0) { ++ error("Error sending audit message."); ++ goto out; ++ } ++ rc = 0; ++ out: ++ free(msg); ++ freecon(default_raw); ++ freecon(selected_raw); ++ close(audit_fd); ++#endif ++ return rc; ++} ++ ++static int ++mls_range_allowed(security_context_t src, security_context_t dst) ++{ ++ struct av_decision avd; ++ int retval; ++ unsigned int bit = CONTEXT__CONTAINS; ++ ++ debug("%s: src:%s dst:%s", __func__, src, dst); ++ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd); ++ if (retval || ((bit & avd.allowed) != bit)) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++get_user_context(const char *sename, const char *role, const char *lvl, ++ security_context_t *sc) { ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) { ++ /* User may have requested a level completely outside of his ++ allowed range. We get a context just for auditing as the ++ range check below will certainly fail for default context. */ ++#endif ++ if (get_default_context(sename, NULL, sc) != 0) { ++ *sc = NULL; ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ } ++#endif ++ if (role != NULL && role[0]) { ++ context_t con; ++ char *type=NULL; ++ if (get_default_type(role, &type) != 0) { ++ error("get_default_type: failed to get default type for '%s'", ++ role); ++ goto out; ++ } ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_role_set(con, role); ++ context_type_set(con, type); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ if (!*sc) ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ if (lvl != NULL && lvl[0]) { ++ /* verify that the requested range is obtained */ ++ context_t con; ++ security_context_t obtained_raw; ++ security_context_t requested_raw; ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_range_set(con, lvl); ++ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) { ++ context_free(con); ++ goto out; ++ } ++ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) { ++ freecon(obtained_raw); ++ context_free(con); ++ goto out; ++ } ++ ++ debug("get_user_context: obtained context '%s' requested context '%s'", ++ obtained_raw, requested_raw); ++ if (strcmp(obtained_raw, requested_raw)) { ++ /* set the context to the real requested one but fail */ ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ return -1; ++ } ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ context_free(con); ++ } ++#endif ++ return 0; ++ out: ++ freecon(*sc); ++ *sc = NULL; ++ return -1; ++} ++ + /* Return the default security context for the given username */ +-static security_context_t +-ssh_selinux_getctxbyname(char *pwname) ++static int ++ssh_selinux_getctxbyname(char *pwname, ++ security_context_t *default_sc, security_context_t *user_sc) + { +- security_context_t sc = NULL; + char *sename, *lvl; ++ const char *reqlvl = NULL; + char *role = NULL; +- int r = 0; ++ int r = -1; ++ context_t con = NULL; ++ ++ *default_sc = NULL; ++ *user_sc = NULL; ++ if (the_authctxt) { ++ if (the_authctxt->role != NULL) { ++ char *slash; ++ role = xstrdup(the_authctxt->role); ++ if ((slash = strchr(role, '/')) != NULL) { ++ *slash = '\0'; ++ reqlvl = slash + 1; ++ } ++ } ++ } + +- if (the_authctxt) +- role=the_authctxt->role; + #ifdef HAVE_GETSEUSERBYNAME + if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { + sename = NULL; +@@ -75,38 +242,63 @@ ssh_selinux_getctxbyname(char *pwname) + } + #else + sename = pwname; +- lvl = NULL; ++ lvl = ""; + #endif + + if (r == 0) { + #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL +- if (role != NULL && role[0]) +- r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc); +- else +- r = get_default_context_with_level(sename, lvl, NULL, &sc); ++ r = get_default_context_with_level(sename, lvl, NULL, default_sc); + #else +- if (role != NULL && role[0]) +- r = get_default_context_with_role(sename, role, NULL, &sc); +- else +- r = get_default_context(sename, NULL, &sc); ++ r = get_default_context(sename, NULL, default_sc); + #endif + } + +- if (r != 0) { +- switch (security_getenforce()) { +- case -1: +- fatal("%s: ssh_selinux_getctxbyname: " +- "security_getenforce() failed", __func__); +- case 0: +- error("%s: Failed to get default SELinux security " +- "context for %s", __func__, pwname); +- break; +- default: +- fatal("%s: Failed to get default SELinux security " +- "context for %s (in enforcing mode)", +- __func__, pwname); ++ if (r == 0) { ++ /* If launched from xinetd, we must use current level */ ++ if (inetd_flag && !rexeced_flag) { ++ security_context_t sshdsc=NULL; ++ ++ if (getcon_raw(&sshdsc) < 0) ++ fatal("failed to allocate security context"); ++ ++ if ((con=context_new(sshdsc)) == NULL) ++ fatal("failed to allocate selinux context"); ++ reqlvl = context_range_get(con); ++ freecon(sshdsc); ++ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) ++ /* we actually don't change level */ ++ reqlvl = ""; ++ ++ debug("%s: current connection level '%s'", __func__, reqlvl); ++ } ++ ++ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) { ++ r = get_user_context(sename, role, reqlvl, user_sc); ++ ++ if (r == 0 && reqlvl != NULL && reqlvl[0]) { ++ security_context_t default_level_sc = *default_sc; ++ if (role != NULL && role[0]) { ++ if (get_user_context(sename, role, lvl, &default_level_sc) < 0) ++ default_level_sc = *default_sc; ++ } ++ /* verify that the requested range is contained in the user range */ ++ if (mls_range_allowed(default_level_sc, *user_sc)) { ++ logit("permit MLS level %s (user range %s)", reqlvl, lvl); ++ } else { ++ r = -1; ++ error("deny MLS level %s (user range %s)", reqlvl, lvl); ++ } ++ if (default_level_sc != *default_sc) ++ freecon(default_level_sc); ++ } ++ } else { ++ *user_sc = *default_sc; + } + } ++ if (r != 0) { ++ error("%s: Failed to get default SELinux security " ++ "context for %s", __func__, pwname); ++ } + + #ifdef HAVE_GETSEUSERBYNAME + if (sename != NULL) +@@ -114,14 +306,20 @@ ssh_selinux_getctxbyname(char *pwname) + if (lvl != NULL) + xfree(lvl); + #endif ++ if (role != NULL) ++ xfree(role); ++ if (con) ++ context_free(con); + +- return (sc); ++ return (r); + } + + /* Set the execution context to the default for the specified user */ + void + ssh_selinux_setup_exec_context(char *pwname) + { ++ int r = 0; ++ security_context_t default_ctx = NULL; + security_context_t user_ctx = NULL; + + if (!ssh_selinux_enabled()) +@@ -129,22 +327,45 @@ ssh_selinux_setup_exec_context(char *pwn + + debug3("%s: setting execution context", __func__); + +- user_ctx = ssh_selinux_getctxbyname(pwname); +- if (setexeccon(user_ctx) != 0) { ++ r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx); ++ if (r >= 0) { ++ r = setexeccon(user_ctx); ++ if (r < 0) { ++ error("%s: Failed to set SELinux execution context %s for %s", ++ __func__, user_ctx, pwname); ++ } ++#ifdef HAVE_SETKEYCREATECON ++ else if (setkeycreatecon(user_ctx) < 0) { ++ error("%s: Failed to set SELinux keyring creation context %s for %s", ++ __func__, user_ctx, pwname); ++ } ++#endif ++ } ++ if (user_ctx == NULL) { ++ user_ctx = default_ctx; ++ } ++ if (r < 0 || user_ctx != default_ctx) { ++ /* audit just the case when user changed a role or there was ++ a failure */ ++ send_audit_message(r >= 0, default_ctx, user_ctx); ++ } ++ if (r < 0) { + switch (security_getenforce()) { + case -1: + fatal("%s: security_getenforce() failed", __func__); + case 0: +- error("%s: Failed to set SELinux execution " +- "context for %s", __func__, pwname); ++ error("%s: SELinux failure. Continuing in permissive mode.", ++ __func__); + break; + default: +- fatal("%s: Failed to set SELinux execution context " +- "for %s (in enforcing mode)", __func__, pwname); ++ fatal("%s: SELinux failure. Aborting connection.", ++ __func__); + } + } +- if (user_ctx != NULL) ++ if (user_ctx != NULL && user_ctx != default_ctx) + freecon(user_ctx); ++ if (default_ctx != NULL) ++ freecon(default_ctx); + + debug3("%s: done", __func__); + } +@@ -162,7 +383,10 @@ ssh_selinux_setup_pty(char *pwname, cons + + debug3("%s: setting TTY context on %s", __func__, tty); + +- user_ctx = ssh_selinux_getctxbyname(pwname); ++ if (getexeccon(&user_ctx) < 0) { ++ error("%s: getexeccon: %s", __func__, strerror(errno)); ++ goto out; ++ } + + /* XXX: should these calls fatal() upon failure in enforcing mode? */ + +diff -up openssh-5.6p1/sshd.c.mls openssh-5.6p1/sshd.c +--- openssh-5.6p1/sshd.c.mls 2010-08-23 12:11:36.000000000 +0200 ++++ openssh-5.6p1/sshd.c 2010-08-23 12:11:37.000000000 +0200 +@@ -1997,6 +1997,9 @@ main(int ac, char **av) + restore_uid(); + } + #endif ++#ifdef WITH_SELINUX ++ ssh_selinux_setup_exec_context(authctxt->pw->pw_name); ++#endif + #ifdef USE_PAM + if (options.use_pam) { + do_pam_setcred(1); diff --git a/openssh-5.6p1-selabel.patch b/openssh-5.6p1-selabel.patch new file mode 100644 index 0000000..459164f --- /dev/null +++ b/openssh-5.6p1-selabel.patch @@ -0,0 +1,53 @@ +diff -up openssh-5.6p1/contrib/ssh-copy-id.selabel openssh-5.6p1/contrib/ssh-copy-id +--- openssh-5.6p1/contrib/ssh-copy-id.selabel 2010-08-10 05:36:09.000000000 +0200 ++++ openssh-5.6p1/contrib/ssh-copy-id 2010-08-23 12:50:20.000000000 +0200 +@@ -41,7 +41,7 @@ fi + # strip any trailing colon + host=`echo $1 | sed 's/:$//'` + +-{ eval "$GET_ID" ; } | ssh $host "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys" || exit 1 ++{ eval "$GET_ID" ; } | ssh $host "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys; test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys" || exit 1 + + cat < + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + #include "openbsd-compat/sys-queue.h" + +@@ -848,10 +849,15 @@ main(int ac, char **av) + */ + r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, + strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); +- if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) ++ if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { ++ char *scon; ++ ++ matchpathcon(buf, 0700, &scon); ++ setfscreatecon(scon); + if (mkdir(buf, 0700) < 0) + error("Could not create directory '%.200s'.", buf); +- ++ setfscreatecon(NULL); ++ } + /* load options.identity_files */ + load_public_identity_files(); + diff --git a/openssh.spec b/openssh.spec index c54bd02..92d712b 100644 --- a/openssh.spec +++ b/openssh.spec @@ -73,7 +73,7 @@ %define openssh_ver 5.6p1 %define openssh_rel 1 %define pam_ssh_agent_ver 0.9.2 -%define pam_ssh_agent_rel 26 +%define pam_ssh_agent_rel 27 Summary: An open source implementation of SSH protocol versions 1 and 2 Name: openssh @@ -94,44 +94,38 @@ Source4: http://prdownloads.sourceforge.net/pamsshagentauth/pam_ssh_agent_auth/p Source5: pam_ssh_agent-rmheaders Patch0: openssh-5.4p1-redhat.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1638 -Patch2: openssh-5.3p1-skip-initial.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1640 Patch4: openssh-5.2p1-vendor.patch Patch10: pam_ssh_agent_auth-0.9-build.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 Patch12: openssh-5.4p1-selinux.patch -Patch13: openssh-5.5p1-mls.patch +Patch13: openssh-5.6p1-mls.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1402 Patch16: openssh-5.3p1-audit.patch Patch18: openssh-5.4p1-pam_selinux.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1663 -Patch20: openssh-5.5p1-authorized-keys-command.patch -Patch21: openssh-5.5p1-ldap.patch +Patch20: openssh-5.6p1-authorized-keys-command.patch +Patch21: openssh-5.6p1-ldap.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1668 -Patch23: openssh-5.5p1-keygen.patch +Patch23: openssh-5.6p1-keygen.patch Patch24: openssh-4.3p1-fromto-remote.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1636 Patch27: openssh-5.1p1-log-in-chroot.patch -Patch30: openssh-4.0p1-exit-deadlock.patch +Patch30: openssh-5.6p1-exit-deadlock.patch Patch35: openssh-5.1p1-askpass-progress.patch Patch38: openssh-4.3p2-askpass-grab-info.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1644 Patch44: openssh-5.2p1-allow-ip-opts.patch Patch49: openssh-4.3p2-gssapi-canohost.patch Patch62: openssh-5.1p1-scp-manpage.patch -Patch65: openssh-5.5p1-fips.patch +Patch65: openssh-5.6p1-fips.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1614 -Patch69: openssh-5.3p1-selabel.patch +Patch69: openssh-5.6p1-selabel.patch Patch71: openssh-5.2p1-edns.patch -Patch73: openssh-5.5p1-gsskex.patch +Patch73: openssh-5.6p1-gsskex.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1701 Patch74: openssh-5.3p1-randclean.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1740 -Patch76: openssh-5.5p1-staterr.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1750 -Patch77: openssh-5.5p1-stderr.patch -Patch78: openssh-5.5p1-kuserok.patch +Patch78: openssh-5.6p1-kuserok.patch Patch79: openssh-5.5p1-x11.patch License: BSD @@ -268,7 +262,6 @@ The module is most useful for su and sudo service stacks. %prep %setup -q -a 4 %patch0 -p1 -b .redhat -%patch2 -p1 -b .skip-initial %patch4 -p1 -b .vendor %if %{pam_ssh_agent} @@ -303,8 +296,6 @@ popd %patch71 -p1 -b .edns %patch73 -p1 -b .gsskex %patch74 -p1 -b .randclean -%patch76 -p1 -b .staterr -%patch77 -p1 -b .stderr %patch78 -p1 -b .kuserok %patch79 -p1 -b .x11