From 190035191329fb89efefd8189969117a94fcaeda Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Jan 20 2015 12:21:45 +0000 Subject: 6.7p1-1 + 0.9.3-4 --- diff --git a/.gitignore b/.gitignore index e407e89..b64821a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /openssh-6.3p1.tar.gz /openssh-6.4p1.tar.gz /openssh-6.6p1.tar.gz +/openssh-6.7p1.tar.gz diff --git a/openssh-5.6p1-exit-deadlock.patch b/openssh-5.6p1-exit-deadlock.patch deleted file mode 100644 index 278dfa1..0000000 --- a/openssh-5.6p1-exit-deadlock.patch +++ /dev/null @@ -1,14 +0,0 @@ -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.9p1-edns.patch b/openssh-5.9p1-edns.patch deleted file mode 100644 index 34f3851..0000000 --- a/openssh-5.9p1-edns.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff -up openssh-5.9p1/dns.c.edns openssh-5.9p1/dns.c ---- openssh-5.9p1/dns.c.edns 2010-08-31 14:41:14.000000000 +0200 -+++ openssh-5.9p1/dns.c 2011-09-09 08:05:27.782440497 +0200 -@@ -177,6 +177,7 @@ verify_host_key_dns(const char *hostname - { - u_int counter; - int result; -+ unsigned int rrset_flags = 0; - struct rrsetinfo *fingerprints = NULL; - - u_int8_t hostkey_algorithm; -@@ -200,8 +201,19 @@ verify_host_key_dns(const char *hostname - return -1; - } - -+ /* -+ * Original getrrsetbyname function, found on OpenBSD for example, -+ * doesn't accept any flag and prerequisite for obtaining AD bit in -+ * DNS response is set by "options edns0" in resolv.conf. -+ * -+ * Our version is more clever and use RRSET_FORCE_EDNS0 flag. -+ */ -+#ifndef HAVE_GETRRSETBYNAME -+ rrset_flags |= RRSET_FORCE_EDNS0; -+#endif - result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, -- DNS_RDATATYPE_SSHFP, 0, &fingerprints); -+ DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints); -+ - if (result) { - verbose("DNS lookup error: %s", dns_result_totext(result)); - return -1; -diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.c ---- openssh-5.9p1/openbsd-compat/getrrsetbyname.c.edns 2009-07-13 03:38:23.000000000 +0200 -+++ openssh-5.9p1/openbsd-compat/getrrsetbyname.c 2011-09-09 15:03:39.930500801 +0200 -@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, uns - goto fail; - } - -- /* don't allow flags yet, unimplemented */ -- if (flags) { -+ /* Allow RRSET_FORCE_EDNS0 flag only. */ -+ if ((flags & ~RRSET_FORCE_EDNS0) != 0) { - result = ERRSET_INVAL; - goto fail; - } -@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, uns - #endif /* DEBUG */ - - #ifdef RES_USE_DNSSEC -- /* turn on DNSSEC if EDNS0 is configured */ -- if (_resp->options & RES_USE_EDNS0) -- _resp->options |= RES_USE_DNSSEC; -+ /* turn on DNSSEC if required */ -+ if (flags & RRSET_FORCE_EDNS0) -+ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC); - #endif /* RES_USE_DNSEC */ - - /* make query */ -diff -up openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns openssh-5.9p1/openbsd-compat/getrrsetbyname.h ---- openssh-5.9p1/openbsd-compat/getrrsetbyname.h.edns 2007-10-26 08:26:50.000000000 +0200 -+++ openssh-5.9p1/openbsd-compat/getrrsetbyname.h 2011-09-09 08:05:27.965438689 +0200 -@@ -72,6 +72,9 @@ - #ifndef RRSET_VALIDATED - # define RRSET_VALIDATED 1 - #endif -+#ifndef RRSET_FORCE_EDNS0 -+# define RRSET_FORCE_EDNS0 0x0001 -+#endif - - /* - * Return codes for getrrsetbyname() diff --git a/openssh-6.2p1-vendor.patch b/openssh-6.2p1-vendor.patch index ddccd2c..583a486 100644 --- a/openssh-6.2p1-vendor.patch +++ b/openssh-6.2p1-vendor.patch @@ -1,7 +1,8 @@ -diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac ---- openssh-6.2p1/configure.ac.vendor 2013-03-25 19:34:01.277495179 +0100 -+++ openssh-6.2p1/configure.ac 2013-03-25 19:34:01.377495818 +0100 -@@ -4420,6 +4420,12 @@ AC_ARG_WITH([lastlog], +diff --git a/configure.ac b/configure.ac +index 6553074..8dedb95 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -4676,6 +4676,12 @@ AC_ARG_WITH([lastlog], fi ] ) @@ -14,7 +15,7 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac dnl lastlog, [uw]tmpx? detection dnl NOTE: set the paths in the platform section to avoid the -@@ -4681,6 +4687,7 @@ echo " Translate v4 in v6 hack +@@ -4938,6 +4944,7 @@ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" echo " BSD Auth support: $BSD_AUTH_MSG" echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" @@ -22,10 +23,11 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac echo "" -diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c ---- openssh-6.2p1/servconf.c.vendor 2013-03-25 19:34:01.197494668 +0100 -+++ openssh-6.2p1/servconf.c 2013-03-25 19:34:01.379495831 +0100 -@@ -128,6 +128,7 @@ initialize_server_options(ServerOptions +diff --git a/servconf.c b/servconf.c +index e3ebaac..c8a3f28 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -141,6 +141,7 @@ initialize_server_options(ServerOptions *options) options->max_authtries = -1; options->max_sessions = -1; options->banner = NULL; @@ -33,17 +35,16 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c options->use_dns = -1; options->client_alive_interval = -1; options->client_alive_count_max = -1; -@@ -287,6 +288,9 @@ fill_default_server_options(ServerOption +@@ -310,6 +311,8 @@ fill_default_server_options(ServerOptions *options) options->ip_qos_bulk = IPTOS_THROUGHPUT; if (options->version_addendum == NULL) options->version_addendum = xstrdup(""); + if (options->show_patchlevel == -1) + options->show_patchlevel = 0; -+ - /* Turn privilege separation on by default */ - if (use_privsep == -1) - use_privsep = PRIVSEP_NOSANDBOX; -@@ -324,7 +328,7 @@ typedef enum { + if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) + options->fwd_opts.streamlocal_bind_mask = 0177; + if (options->fwd_opts.streamlocal_bind_unlink == -1) +@@ -353,7 +356,7 @@ typedef enum { sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, @@ -52,7 +53,7 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, -@@ -439,6 +443,7 @@ static struct { +@@ -467,6 +470,7 @@ static struct { { "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, { "maxsessions", sMaxSessions, SSHCFG_ALL }, { "banner", sBanner, SSHCFG_ALL }, @@ -60,7 +61,7 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c { "usedns", sUseDNS, SSHCFG_GLOBAL }, { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, -@@ -1163,6 +1168,10 @@ process_server_config_line(ServerOptions +@@ -1263,6 +1267,10 @@ process_server_config_line(ServerOptions *options, char *line, multistate_ptr = multistate_privsep; goto parse_multistate; @@ -71,18 +72,19 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) -@@ -1950,6 +1959,7 @@ dump_config(ServerOptions *o) +@@ -2081,6 +2089,7 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sUseLogin, o->use_login); dump_cfg_fmtint(sCompression, o->compression); - dump_cfg_fmtint(sGatewayPorts, o->gateway_ports); + dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); + dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel); dump_cfg_fmtint(sUseDNS, o->use_dns); dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); -diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h ---- openssh-6.2p1/servconf.h.vendor 2013-01-09 05:56:45.000000000 +0100 -+++ openssh-6.2p1/servconf.h 2013-03-25 19:34:01.379495831 +0100 -@@ -147,6 +147,7 @@ typedef struct { + dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); +diff --git a/servconf.h b/servconf.h +index 49b228b..21719e2 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -149,6 +149,7 @@ typedef struct { int max_authtries; int max_sessions; char *banner; /* SSH-2 banner message */ @@ -90,10 +92,34 @@ diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h int use_dns; int client_alive_interval; /* * poke the client this often to -diff -up openssh-6.2p1/sshd_config.vendor openssh-6.2p1/sshd_config ---- openssh-6.2p1/sshd_config.vendor 2013-03-25 19:34:01.380495837 +0100 -+++ openssh-6.2p1/sshd_config 2013-03-25 19:44:43.471296362 +0100 -@@ -118,6 +118,7 @@ UsePrivilegeSeparation sandbox # Defaul +diff --git a/sshd.c b/sshd.c +index afe9afa..193b206 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -432,7 +432,7 @@ sshd_exchange_identification(int sock_in, int sock_out) + } + + xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", +- major, minor, SSH_VERSION, ++ major, minor, (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, + *options.version_addendum == '\0' ? "" : " ", + options.version_addendum, newline); + +@@ -1677,7 +1677,8 @@ main(int ac, char **av) + exit(1); + } + +- debug("sshd version %s, %s", SSH_VERSION, ++ debug("sshd version %s, %s", ++ (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, + #ifdef WITH_OPENSSL + SSLeay_version(SSLEAY_VERSION) + #else +diff --git a/sshd_config b/sshd_config +index 3092ac6..da3db5d 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -119,6 +119,7 @@ UsePrivilegeSeparation sandbox # Default for new installations. #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 @@ -101,10 +127,11 @@ diff -up openssh-6.2p1/sshd_config.vendor openssh-6.2p1/sshd_config #UseDNS yes #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 -diff -up openssh-6.2p1/sshd_config.0.vendor openssh-6.2p1/sshd_config.0 ---- openssh-6.2p1/sshd_config.0.vendor 2013-03-25 19:34:01.361495716 +0100 -+++ openssh-6.2p1/sshd_config.0 2013-03-25 19:34:01.381495844 +0100 -@@ -595,6 +595,11 @@ DESCRIPTION +diff --git a/sshd_config.0 b/sshd_config.0 +index 43867d3..a3898c3 100644 +--- a/sshd_config.0 ++++ b/sshd_config.0 +@@ -700,6 +700,11 @@ DESCRIPTION Defines the number of bits in the ephemeral protocol version 1 server key. The minimum value is 512, and the default is 1024. @@ -113,13 +140,14 @@ diff -up openssh-6.2p1/sshd_config.0.vendor openssh-6.2p1/sshd_config.0 + the binary in the server identification string. The patch level + is set at compile-time. The default is M-bM-^@M-^\noM-bM-^@M-^]. + - StrictModes - Specifies whether sshd(8) should check file modes and ownership - of the user's files and home directory before accepting login. -diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5 ---- openssh-6.2p1/sshd_config.5.vendor 2013-03-25 19:34:01.362495722 +0100 -+++ openssh-6.2p1/sshd_config.5 2013-03-25 19:34:01.382495850 +0100 -@@ -1019,6 +1019,14 @@ This option applies to protocol version + StreamLocalBindMask + Sets the octal file creation mode mask (umask) used when creating + a Unix-domain socket file for local or remote port forwarding. +diff --git a/sshd_config.5 b/sshd_config.5 +index 89a0cf2..cccb310 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1200,6 +1200,13 @@ This option applies to protocol version 1 only. .It Cm ServerKeyBits Defines the number of bits in the ephemeral protocol version 1 server key. The minimum value is 512, and the default is 1024. @@ -130,29 +158,6 @@ diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5 +The patch level is set at compile-time. +The default is +.Dq no . -+This option applies to protocol version 1 only. - .It Cm StrictModes - Specifies whether - .Xr sshd 8 -diff -up openssh-6.2p1/sshd.c.vendor openssh-6.2p1/sshd.c ---- openssh-6.2p1/sshd.c.vendor 2013-03-25 19:34:01.332495531 +0100 -+++ openssh-6.2p1/sshd.c 2013-03-25 19:44:11.864112092 +0100 -@@ -442,7 +442,7 @@ sshd_exchange_identification(int sock_in - } - - xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", -- major, minor, SSH_VERSION, -+ major, minor, (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, - *options.version_addendum == '\0' ? "" : " ", - options.version_addendum, newline); - -@@ -1675,7 +1675,8 @@ main(int ac, char **av) - exit(1); - } - -- debug("sshd version %s, %s", SSH_VERSION, -+ debug("sshd version %s, %s", -+ (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, - SSLeay_version(SSLEAY_VERSION)); - - /* Store privilege separation user for later use if required. */ + .It Cm StreamLocalBindMask + Sets the octal file creation mode mask + .Pq umask diff --git a/openssh-6.6.1p1-audit-pfs.patch b/openssh-6.6.1p1-audit-pfs.patch deleted file mode 100644 index 35be907..0000000 --- a/openssh-6.6.1p1-audit-pfs.patch +++ /dev/null @@ -1,212 +0,0 @@ -diff --git a/audit-bsm.c b/audit-bsm.c -index 5160869..c7a1b47 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -481,7 +481,7 @@ audit_unsupported_body(int what) - } - - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid) -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) - { - /* not implemented */ - } -diff --git a/audit-linux.c b/audit-linux.c -index 6954fc1..6686f6a 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -297,7 +297,7 @@ audit_unsupported_body(int what) - const static char *direction[] = { "from-server", "from-client", "both" }; - - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, - uid_t uid) - { - #ifdef AUDIT_CRYPTO_SESSION -@@ -306,8 +306,8 @@ audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, - Cipher *cipher = cipher_by_name(enc); - char *s; - -- snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -- direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, -+ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, - (intmax_t)pid, (intmax_t)uid, - get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); - free(s); -diff --git a/audit.c b/audit.c -index 13c6849..5b49434 100644 ---- a/audit.c -+++ b/audit.c -@@ -135,9 +135,9 @@ audit_unsupported(int what) - } - - void --audit_kex(int ctos, char *enc, char *mac, char *comp) -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) - { -- PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); - } - - void -@@ -270,11 +270,11 @@ audit_unsupported_body(int what) - * This will be called on succesfull protocol negotiation. - */ - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, - uid_t uid) - { -- debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", -- (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, - (unsigned)uid); - } - -diff --git a/audit.h b/audit.h -index a2dc3ff..903df66 100644 ---- a/audit.h -+++ b/audit.h -@@ -61,9 +61,9 @@ ssh_audit_event_t audit_classify_auth(const char *); - int audit_keyusage(int, const char *, unsigned, char *, int); - void audit_key(int, int *, const Key *); - void audit_unsupported(int); --void audit_kex(int, char *, char *, char *); -+void audit_kex(int, char *, char *, char *, char *); - void audit_unsupported_body(int); --void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); - void audit_session_key_free(int ctos); - void audit_session_key_free_body(int ctos, pid_t, uid_t); - void audit_destroy_sensitive_data(const char *, pid_t, uid_t); -diff --git a/auditstub.c b/auditstub.c -index 45817e0..116f460 100644 ---- a/auditstub.c -+++ b/auditstub.c -@@ -35,7 +35,7 @@ audit_unsupported(int n) - } - - void --audit_kex(int ctos, char *enc, char *mac, char *comp) -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) - { - } - -diff --git a/kex.c b/kex.c -index ede7b67..eb5f333 100644 ---- a/kex.c -+++ b/kex.c -@@ -553,13 +553,12 @@ kex_choose_conf(Kex *kex) - newkeys->enc.name, - authlen == 0 ? newkeys->mac.name : "", - newkeys->comp.name); --#ifdef SSH_AUDIT_EVENTS -- audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); --#endif - } -+ - choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], - sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); -+ - need = dh_need = 0; - for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = kex->newkeys[mode]; -@@ -571,11 +570,16 @@ kex_choose_conf(Kex *kex) - dh_need = MAX(dh_need, newkeys->enc.block_size); - dh_need = MAX(dh_need, newkeys->enc.iv_len); - dh_need = MAX(dh_need, newkeys->mac.key_len); -+ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); -+#endif - } - /* XXX need runden? */ - kex->we_need = need; - kex->dh_need = dh_need; - -+ - /* ignore the next message if the proposals do not match */ - if (first_kex_follows && !proposals_match(my, peer) && - !(datafellows & SSH_BUG_FIRSTKEX)) { -diff --git a/monitor.c b/monitor.c -index 70b9b4c..81bc9c1 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2396,7 +2396,7 @@ int - mm_answer_audit_kex_body(int sock, Buffer *m) - { - int ctos, len; -- char *cipher, *mac, *compress; -+ char *cipher, *mac, *compress, *pfs; - pid_t pid; - uid_t uid; - -@@ -2404,14 +2404,16 @@ mm_answer_audit_kex_body(int sock, Buffer *m) - cipher = buffer_get_string(m, &len); - mac = buffer_get_string(m, &len); - compress = buffer_get_string(m, &len); -+ pfs = buffer_get_string(m, &len); - pid = buffer_get_int64(m); - uid = buffer_get_int64(m); - -- audit_kex_body(ctos, cipher, mac, compress, pid, uid); -+ audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); - - free(cipher); - free(mac); - free(compress); -+ free(pfs); - buffer_clear(m); - - mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 93f6535..69b29d8 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -1408,7 +1408,7 @@ mm_audit_unsupported_body(int what) - } - - void --mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, - uid_t uid) - { - Buffer m; -@@ -1418,6 +1418,7 @@ mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, - buffer_put_cstring(&m, cipher); - buffer_put_cstring(&m, (mac ? mac : "")); - buffer_put_cstring(&m, compress); -+ buffer_put_cstring(&m, fps); - buffer_put_int64(&m, pid); - buffer_put_int64(&m, uid); - -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 4cf0c78..e43109f 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -83,7 +83,7 @@ void mm_audit_event(ssh_audit_event_t); - int mm_audit_run_command(const char *); - void mm_audit_end_command(int, const char *); - void mm_audit_unsupported_body(int); --void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); - void mm_audit_session_key_free_body(int, pid_t, uid_t); - void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); - #endif -diff --git a/sshd.c b/sshd.c -index ee94825..41a94a7 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2430,7 +2430,7 @@ do_ssh1_kex(void) - packet_disconnect("IP Spoofing check bytes do not match."); - - #ifdef SSH_AUDIT_EVENTS -- audit_kex(2, cipher_name(cipher_type), "crc", "none"); -+ audit_kex(2, cipher_name(cipher_type), "crc", "none", "none"); - #endif - - debug("Encryption type: %.200s", cipher_name(cipher_type)); diff --git a/openssh-6.6.1p1-log-in-chroot.patch b/openssh-6.6.1p1-log-in-chroot.patch index bccf39b..bca27be 100644 --- a/openssh-6.6.1p1-log-in-chroot.patch +++ b/openssh-6.6.1p1-log-in-chroot.patch @@ -40,10 +40,10 @@ index ae7df25..30c3310 100644 int log_is_on_stderr(void); void log_redirect_stderr_to(const char *); diff --git a/monitor.c b/monitor.c -index 7461fae..da2f766 100644 +index 7ebc76e..d97e640 100644 --- a/monitor.c +++ b/monitor.c -@@ -364,6 +364,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) +@@ -378,6 +378,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) close(pmonitor->m_log_sendfd); pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; @@ -52,7 +52,7 @@ index 7461fae..da2f766 100644 authctxt = _authctxt; memset(authctxt, 0, sizeof(*authctxt)); -@@ -472,6 +474,8 @@ monitor_child_postauth(struct monitor *pmonitor) +@@ -486,6 +488,8 @@ monitor_child_postauth(struct monitor *pmonitor) close(pmonitor->m_recvfd); pmonitor->m_recvfd = -1; @@ -61,7 +61,7 @@ index 7461fae..da2f766 100644 monitor_set_child_handler(pmonitor->m_pid); signal(SIGHUP, &monitor_child_handler); signal(SIGTERM, &monitor_child_handler); -@@ -552,7 +556,7 @@ monitor_read_log(struct monitor *pmonitor) +@@ -566,7 +570,7 @@ monitor_read_log(struct monitor *pmonitor) if (log_level_name(level) == NULL) fatal("%s: invalid log level %u (corrupted message?)", __func__, level); @@ -70,7 +70,7 @@ index 7461fae..da2f766 100644 buffer_free(&logmsg); free(msg); -@@ -2083,13 +2087,28 @@ monitor_init(void) +@@ -2107,13 +2111,28 @@ monitor_init(void) mm_init_compression(mon->m_zlib); } @@ -119,7 +119,7 @@ index ff79fbb..00c2028 100644 struct Authctxt; diff --git a/session.c b/session.c -index e4add93..bc4a8dd 100644 +index 9c94d8e..40a681e 100644 --- a/session.c +++ b/session.c @@ -160,6 +160,8 @@ login_cap_t *lc; @@ -131,7 +131,7 @@ index e4add93..bc4a8dd 100644 /* Name and directory of socket for authentication agent forwarding. */ static char *auth_sock_name = NULL; static char *auth_sock_dir = NULL; -@@ -523,8 +525,8 @@ do_exec_no_pty(Session *s, const char *command) +@@ -505,8 +507,8 @@ do_exec_no_pty(Session *s, const char *command) is_child = 1; /* Child. Reinitialize the log since the pid has changed. */ @@ -142,7 +142,7 @@ index e4add93..bc4a8dd 100644 /* * Create a new session and process group since the 4.4BSD -@@ -692,8 +694,8 @@ do_exec_pty(Session *s, const char *command) +@@ -674,8 +676,8 @@ do_exec_pty(Session *s, const char *command) close(ptymaster); /* Child. Reinitialize the log because the pid has changed. */ @@ -153,7 +153,7 @@ index e4add93..bc4a8dd 100644 /* Close the master side of the pseudo tty. */ close(ptyfd); -@@ -797,6 +799,7 @@ do_exec(Session *s, const char *command) +@@ -779,6 +781,7 @@ do_exec(Session *s, const char *command) int ret; const char *forced = NULL; char session_type[1024], *tty = NULL; @@ -161,7 +161,7 @@ index e4add93..bc4a8dd 100644 if (options.adm_forced_command) { original_command = command; -@@ -854,6 +857,10 @@ do_exec(Session *s, const char *command) +@@ -836,6 +839,10 @@ do_exec(Session *s, const char *command) tty += 5; } @@ -172,7 +172,7 @@ index e4add93..bc4a8dd 100644 verbose("Starting session: %s%s%s for %s from %.200s port %d", session_type, tty == NULL ? "" : " on ", -@@ -1681,14 +1688,6 @@ child_close_fds(void) +@@ -1677,14 +1684,6 @@ child_close_fds(void) * descriptors left by system functions. They will be closed later. */ endpwent(); @@ -187,7 +187,7 @@ index e4add93..bc4a8dd 100644 } /* -@@ -1834,8 +1833,6 @@ do_child(Session *s, const char *command) +@@ -1830,8 +1829,6 @@ do_child(Session *s, const char *command) exit(1); } @@ -196,7 +196,7 @@ index e4add93..bc4a8dd 100644 if (!options.use_login) do_rc_files(s, shell); -@@ -1859,9 +1856,17 @@ do_child(Session *s, const char *command) +@@ -1855,9 +1852,17 @@ do_child(Session *s, const char *command) argv[i] = NULL; optind = optreset = 1; __progname = argv[0]; @@ -227,10 +227,10 @@ index 7e644ab..e162b7a 100644 + return (sftp_server_main(argc, argv, user_pw, 0)); } diff --git a/sftp-server.c b/sftp-server.c -index b8eb59c..a0e644c 100644 +index 0177130..8fa7fc7 100644 --- a/sftp-server.c +++ b/sftp-server.c -@@ -1437,7 +1437,7 @@ sftp_server_usage(void) +@@ -1440,7 +1440,7 @@ sftp_server_usage(void) } int @@ -239,7 +239,7 @@ index b8eb59c..a0e644c 100644 { fd_set *rset, *wset; int i, in, out, max, ch, skipargs = 0, log_stderr = 0; -@@ -1450,7 +1450,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) +@@ -1453,7 +1453,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) extern char *__progname; __progname = ssh_get_progname(argv[0]); @@ -248,15 +248,15 @@ index b8eb59c..a0e644c 100644 pw = pwcopy(user_pw); -@@ -1521,7 +1521,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) +@@ -1524,7 +1524,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) } } - log_init(__progname, log_level, log_facility, log_stderr); + log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); - if ((cp = getenv("SSH_CONNECTION")) != NULL) { - client_addr = xstrdup(cp); + #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + /* diff --git a/sftp.h b/sftp.h index 2bde8bb..ddf1a39 100644 --- a/sftp.h @@ -269,10 +269,10 @@ index 2bde8bb..ddf1a39 100644 +int sftp_server_main(int, char **, struct passwd *, int); void sftp_server_cleanup_exit(int) __attribute__((noreturn)); diff --git a/sshd.c b/sshd.c -index 3eee75a..9c00bcb 100644 +index 39b9c08..ca55d7f 100644 --- a/sshd.c +++ b/sshd.c -@@ -745,7 +745,7 @@ privsep_postauth(Authctxt *authctxt) +@@ -737,7 +737,7 @@ privsep_postauth(Authctxt *authctxt) } /* New socket pair */ @@ -281,7 +281,7 @@ index 3eee75a..9c00bcb 100644 pmonitor->m_pid = fork(); if (pmonitor->m_pid == -1) -@@ -763,6 +763,11 @@ privsep_postauth(Authctxt *authctxt) +@@ -755,6 +755,11 @@ privsep_postauth(Authctxt *authctxt) close(pmonitor->m_sendfd); pmonitor->m_sendfd = -1; diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch index a831a15..425ffda 100644 --- a/openssh-6.6.1p1-selinux-contexts.patch +++ b/openssh-6.6.1p1-selinux-contexts.patch @@ -1,16 +1,16 @@ diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index 0077dd7..e3f2ced 100644 +index 8f32464..18a2ca4 100644 --- a/openbsd-compat/port-linux-sshd.c +++ b/openbsd-compat/port-linux-sshd.c -@@ -31,6 +31,7 @@ - #include "xmalloc.h" +@@ -32,6 +32,7 @@ + #include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ #include "servconf.h" #include "port-linux.h" +#include "misc.h" #include "key.h" #include "hostfile.h" #include "auth.h" -@@ -444,7 +445,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname) void sshd_selinux_copy_context(void) { @@ -19,7 +19,7 @@ index 0077dd7..e3f2ced 100644 if (!sshd_selinux_enabled()) return; -@@ -460,6 +461,58 @@ sshd_selinux_copy_context(void) +@@ -461,6 +462,58 @@ sshd_selinux_copy_context(void) } } @@ -104,10 +104,10 @@ index cb51f99..8b7cda2 100644 #ifdef LINUX_OOM_ADJUST diff --git a/sshd.c b/sshd.c -index 512c7ed..3eee75a 100644 +index 2871fe9..39b9c08 100644 --- a/sshd.c +++ b/sshd.c -@@ -637,7 +637,7 @@ privsep_preauth_child(void) +@@ -629,7 +629,7 @@ privsep_preauth_child(void) demote_sensitive_data(); #ifdef WITH_SELINUX diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/openssh-6.6p1-GSSAPIEnablek5users.patch index a60d608..a51e199 100644 --- a/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -1,5 +1,5 @@ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 0a4930e..a7c0c5f 100644 +index 961c564..0fcfd7b 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -260,7 +260,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, @@ -20,27 +20,27 @@ index 0a4930e..a7c0c5f 100644 k5login_exists); } diff --git a/servconf.c b/servconf.c -index d482e79..ad5869b 100644 +index e4164b1..87a311b 100644 --- a/servconf.c +++ b/servconf.c -@@ -158,6 +158,7 @@ initialize_server_options(ServerOptions *options) - options->ip_qos_bulk = -1; +@@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options) options->version_addendum = NULL; + options->fingerprint_hash = -1; options->use_kuserok = -1; + options->enable_k5users = -1; } void -@@ -315,6 +316,8 @@ fill_default_server_options(ServerOptions *options) - options->show_patchlevel = 0; +@@ -331,6 +332,8 @@ fill_default_server_options(ServerOptions *options) + options->fingerprint_hash = SSH_FP_HASH_DEFAULT; if (options->use_kuserok == -1) options->use_kuserok = 1; + if (options->enable_k5users == -1) + options->enable_k5users = 0; - /* Turn privilege separation on by default */ if (use_privsep == -1) -@@ -356,7 +359,7 @@ typedef enum { + use_privsep = PRIVSEP_NOSANDBOX; +@@ -371,7 +374,7 @@ typedef enum { sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, @@ -49,7 +49,7 @@ index d482e79..ad5869b 100644 sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -430,6 +433,7 @@ static struct { +@@ -447,6 +450,7 @@ static struct { { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, @@ -57,7 +57,7 @@ index d482e79..ad5869b 100644 #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -@@ -437,6 +441,7 @@ static struct { +@@ -454,6 +458,7 @@ static struct { { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, @@ -65,7 +65,7 @@ index d482e79..ad5869b 100644 #endif { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, -@@ -1536,6 +1541,10 @@ process_server_config_line(ServerOptions *options, char *line, +@@ -1566,6 +1571,10 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->use_kuserok; goto parse_flag; @@ -76,7 +76,7 @@ index d482e79..ad5869b 100644 case sPermitOpen: arg = strdelim(&cp); if (!arg || *arg == '\0') -@@ -1824,6 +1833,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) +@@ -1884,6 +1893,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); M_CP_INTOPT(use_kuserok); @@ -84,19 +84,19 @@ index d482e79..ad5869b 100644 M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); -@@ -2076,6 +2086,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); +@@ -2143,6 +2153,7 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); + dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users); /* string arguments */ dump_cfg_string(sPidFile, o->pid_file); diff --git a/servconf.h b/servconf.h -index 5117dfa..d63cb71 100644 +index cf2a505..070a8ed 100644 --- a/servconf.h +++ b/servconf.h -@@ -173,7 +173,8 @@ typedef struct { +@@ -175,7 +175,8 @@ typedef struct { int num_permitted_opens; @@ -107,7 +107,7 @@ index 5117dfa..d63cb71 100644 char *revoked_keys_file; char *trusted_user_ca_keys; diff --git a/sshd_config b/sshd_config -index 43671f6..6ab00ed 100644 +index 0d9454d..e731de1 100644 --- a/sshd_config +++ b/sshd_config @@ -94,6 +94,7 @@ GSSAPIAuthentication yes @@ -119,10 +119,10 @@ index 43671f6..6ab00ed 100644 # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will diff --git a/sshd_config.5 b/sshd_config.5 -index e0e5fff..aa9525d 100644 +index eb4dd9e..ce1229b 100644 --- a/sshd_config.5 +++ b/sshd_config.5 -@@ -505,6 +505,12 @@ on logout. +@@ -548,6 +548,12 @@ on logout. The default is .Dq yes . Note that this option applies to protocol version 2 only. diff --git a/openssh-6.6p1-audit.patch b/openssh-6.6p1-audit.patch deleted file mode 100644 index 2ee2012..0000000 --- a/openssh-6.6p1-audit.patch +++ /dev/null @@ -1,2312 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 0f0d39f..9d8c2eb 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -82,7 +82,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ - ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \ -- sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o -+ sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ -+ auditstub.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o \ -diff --git a/audit-bsm.c b/audit-bsm.c -index 6135591..5160869 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -375,10 +375,23 @@ audit_connection_from(const char *host, int port) - #endif - } - --void -+int - audit_run_command(const char *command) - { - /* not implemented */ -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_count_session_open(void) -+{ -+ /* not necessary */ - } - - void -@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li) - /* not implemented */ - } - -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ /* not implemented */ -+} -+ - void - audit_event(ssh_audit_event_t event) - { -@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) - debug("%s: unhandled event %d", __func__, event); - } - } -+ -+void -+audit_unsupported_body(int what) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_generate_ephemeral_server_key(const char *fp) -+{ -+ /* not implemented */ -+} - #endif /* BSM */ -diff --git a/audit-linux.c b/audit-linux.c -index b3ee2f4..946f7fa 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -35,13 +35,24 @@ - - #include "log.h" - #include "audit.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+#include "servconf.h" - #include "canohost.h" -+#include "packet.h" -+#include "cipher.h" - -+#define AUDIT_LOG_SIZE 256 -+ -+extern ServerOptions options; -+extern Authctxt *the_authctxt; -+extern u_int utmp_len; - const char* audit_username(void); - --int --linux_audit_record_event(int uid, const char *username, -- const char *hostname, const char *ip, const char *ttyn, int success) -+static void -+linux_audit_user_logxxx(int uid, const char *username, -+ const char *hostname, const char *ip, const char *ttyn, int success, int event) - { - int audit_fd, rc, saved_errno; - -@@ -49,11 +60,11 @@ linux_audit_record_event(int uid, const char *username, - if (audit_fd < 0) { - if (errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT) -- return 1; /* No audit support in kernel */ -+ return; /* No audit support in kernel */ - else -- return 0; /* Must prevent login */ -+ goto fatal_report; /* Must prevent login */ - } -- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, -+ rc = audit_log_acct_message(audit_fd, event, - NULL, "login", username ? username : "(unknown)", - username == NULL ? uid : -1, hostname, ip, ttyn, success); - saved_errno = errno; -@@ -65,35 +76,150 @@ linux_audit_record_event(int uid, const char *username, - if ((rc == -EPERM) && (geteuid() != 0)) - rc = 0; - errno = saved_errno; -- return (rc >= 0); -+ if (rc < 0) { -+fatal_report: -+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ } - } - -+static void -+linux_audit_user_auth(int uid, const char *username, -+ const char *hostname, const char *ip, const char *ttyn, int success, int event) -+{ -+ int audit_fd, rc, saved_errno; -+ static const char *event_name[] = { -+ "maxtries exceeded", -+ "root denied", -+ "success", -+ "none", -+ "password", -+ "challenge-response", -+ "pubkey", -+ "hostbased", -+ "gssapi", -+ "invalid user", -+ "nologin", -+ "connection closed", -+ "connection abandoned", -+ "unknown" -+ }; -+ -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return; /* No audit support in kernel */ -+ else -+ goto fatal_report; /* Must prevent login */ -+ } -+ -+ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) -+ event = SSH_AUDIT_UNKNOWN; -+ -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, -+ NULL, event_name[event], username ? username : "(unknown)", -+ username == NULL ? uid : -1, hostname, ip, ttyn, success); -+ saved_errno = errno; -+ close(audit_fd); -+ /* -+ * Do not report error if the error is EPERM and sshd is run as non -+ * root user. -+ */ -+ if ((rc == -EPERM) && (geteuid() != 0)) -+ rc = 0; -+ errno = saved_errno; -+ if (rc < 0) { -+fatal_report: -+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ } -+} -+ -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, rc, saved_errno; -+ -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return 1; /* No audit support in kernel */ -+ else -+ return 0; /* Must prevent login */ -+ } -+ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", -+ type, bits, key_fingerprint_prefix(), fp, get_remote_port()); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); -+out: -+ saved_errno = errno; -+ audit_close(audit_fd); -+ errno = saved_errno; -+ /* do not report error if the error is EPERM and sshd is run as non root user */ -+ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); -+} -+ -+static int user_login_count = 0; -+ - /* Below is the sshd audit API code */ - - void - audit_connection_from(const char *host, int port) - { --} - /* not implemented */ -+} - --void -+int - audit_run_command(const char *command) - { -- /* not implemented */ -+ if (!user_login_count++) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_START); -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+} -+ -+void -+audit_count_session_open(void) -+{ -+ user_login_count++; - } - - void - audit_session_open(struct logininfo *li) - { -- if (linux_audit_record_event(li->uid, NULL, li->hostname, -- NULL, li->line, 1) == 0) -- fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ if (!user_login_count++) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_START); - } - - void - audit_session_close(struct logininfo *li) - { -- /* not implemented */ -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGOUT); - } - - void -@@ -101,21 +227,43 @@ audit_event(ssh_audit_event_t event) - { - switch(event) { - case SSH_AUTH_SUCCESS: -- case SSH_CONNECTION_CLOSE: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 1, event); -+ break; -+ - case SSH_NOLOGIN: -- case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_LOGIN_ROOT_DENIED: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - -+ case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_AUTH_FAIL_NONE: - case SSH_AUTH_FAIL_PASSWD: - case SSH_AUTH_FAIL_KBDINT: - case SSH_AUTH_FAIL_PUBKEY: - case SSH_AUTH_FAIL_HOSTBASED: - case SSH_AUTH_FAIL_GSSAPI: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ break; -+ -+ case SSH_CONNECTION_CLOSE: -+ if (user_login_count) { -+ while (user_login_count--) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+ } -+ break; -+ -+ case SSH_CONNECTION_ABANDON: - case SSH_INVALID_USER: -- linux_audit_record_event(-1, audit_username(), NULL, -- get_remote_ipaddr(), "sshd", 0); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - - default: -@@ -123,4 +271,135 @@ audit_event(ssh_audit_event_t event) - } - } - -+void -+audit_unsupported_body(int what) -+{ -+#ifdef AUDIT_CRYPTO_SESSION -+ char buf[AUDIT_LOG_SIZE]; -+ const static char *name[] = { "cipher", "mac", "comp" }; -+ char *s; -+ int audit_fd; -+ -+ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", -+ name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), -+ get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) -+ /* no problem, the next instruction will be fatal() */ -+ return; -+ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, get_remote_ipaddr(), NULL, 0); -+ audit_close(audit_fd); -+#endif -+} -+ -+const static char *direction[] = { "from-server", "from-client", "both" }; -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+ uid_t uid) -+{ -+#ifdef AUDIT_CRYPTO_SESSION -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ Cipher *cipher = cipher_by_name(enc); -+ char *s; -+ -+ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, -+ (intmax_t)pid, (intmax_t)uid, -+ get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return; /* No audit support in kernel */ -+ else -+ fatal("cannot open audit"); /* Must prevent login */ -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, get_remote_ipaddr(), NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ fatal("cannot write into audit"); /* Must prevent login */ -+#endif -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ char *s; -+ -+ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], (intmax_t)pid, (intmax_t)uid, -+ get_remote_port(), -+ (s = get_local_ipaddr(packet_get_connection_in())), -+ get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, get_remote_ipaddr(), NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ -+ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", -+ fp, (intmax_t)pid, (intmax_t)uid); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, -+ listening_for_clients() ? NULL : get_remote_ipaddr(), -+ NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} -+ -+void -+audit_generate_ephemeral_server_key(const char *fp) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ -+ snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, 0, NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} - #endif /* USE_LINUX_AUDIT */ -diff --git a/audit.c b/audit.c -index ced57fa..ab9fb82 100644 ---- a/audit.c -+++ b/audit.c -@@ -28,6 +28,7 @@ - - #include - #include -+#include - - #ifdef SSH_AUDIT_EVENTS - -@@ -36,6 +37,9 @@ - #include "key.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "xmalloc.h" - - /* - * Care must be taken when using this since it WILL NOT be initialized when -@@ -71,13 +75,10 @@ audit_classify_auth(const char *method) - const char * - audit_username(void) - { -- static const char unknownuser[] = "(unknown user)"; -- static const char invaliduser[] = "(invalid user)"; -+ static const char unknownuser[] = "(unknown)"; - -- if (the_authctxt == NULL || the_authctxt->user == NULL) -+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) - return (unknownuser); -- if (!the_authctxt->valid) -- return (invaliduser); - return (the_authctxt->user); - } - -@@ -111,6 +112,40 @@ audit_event_lookup(ssh_audit_event_t ev) - return(event_lookup[i].name); - } - -+void -+audit_key(int host_user, int *rv, const Key *key) -+{ -+ char *fp; -+ const char *crypto_name; -+ -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ if (key->type == KEY_RSA1) -+ crypto_name = "ssh-rsa1"; -+ else -+ crypto_name = key_ssh_name(key); -+ if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) -+ *rv = 0; -+ free(fp); -+} -+ -+void -+audit_unsupported(int what) -+{ -+ PRIVSEP(audit_unsupported_body(what)); -+} -+ -+void -+audit_kex(int ctos, char *enc, char *mac, char *comp) -+{ -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); -+} -+ -+void -+audit_session_key_free(int ctos) -+{ -+ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); -+} -+ - # ifndef CUSTOM_SSH_AUDIT_EVENTS - /* - * Null implementations of audit functions. -@@ -140,6 +175,17 @@ audit_event(ssh_audit_event_t event) - } - - /* -+ * Called when a child process has called, or will soon call, -+ * audit_session_open. -+ */ -+void -+audit_count_session_open(void) -+{ -+ debug("audit count session open euid %d user %s", geteuid(), -+ audit_username()); -+} -+ -+/* - * Called when a user session is started. Argument is the tty allocated to - * the session, or NULL if no tty was allocated. - * -@@ -174,13 +220,91 @@ audit_session_close(struct logininfo *li) - /* - * This will be called when a user runs a non-interactive command. Note that - * it may be called multiple times for a single connection since SSH2 allows -- * multiple sessions within a single connection. -+ * multiple sessions within a single connection. Returns a "handle" for -+ * audit_end_command. - */ --void -+int - audit_run_command(const char *command) - { - debug("audit run command euid %d user %s command '%.200s'", geteuid(), - audit_username(), command); -+ return 0; -+} -+ -+/* -+ * This will be called when the non-interactive command finishes. Note that -+ * it may be called multiple times for a single connection since SSH2 allows -+ * multiple sessions within a single connection. "handle" should come from -+ * the corresponding audit_run_command. -+ */ -+void -+audit_end_command(int handle, const char *command) -+{ -+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), -+ audit_username(), command); -+} -+ -+/* -+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. -+ * -+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. -+ */ -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", -+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, -+ key_fingerprint_prefix(), fp, rv); -+} -+ -+/* -+ * This will be called when the protocol negotiation fails. -+ */ -+void -+audit_unsupported_body(int what) -+{ -+ debug("audit unsupported protocol euid %d type %d", geteuid(), what); -+} -+ -+/* -+ * This will be called on succesfull protocol negotiation. -+ */ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+ uid_t uid) -+{ -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, -+ (unsigned)uid); -+} -+ -+/* -+ * This will be called on succesfull session key discard -+ */ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ debug("audit session key discard euid %u direction %d from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on destroy private part of the server key -+ */ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", -+ geteuid(), fp, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on generation of the ephemeral server key -+ */ -+void -+audit_generate_ephemeral_server_key(const char *) -+{ -+ debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); - } - # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ - #endif /* SSH_AUDIT_EVENTS */ -diff --git a/audit.h b/audit.h -index 92ede5b..a2dc3ff 100644 ---- a/audit.h -+++ b/audit.h -@@ -28,6 +28,7 @@ - # define _SSH_AUDIT_H - - #include "loginrec.h" -+#include "key.h" - - enum ssh_audit_event_type { - SSH_LOGIN_EXCEED_MAXTRIES, -@@ -47,11 +48,25 @@ enum ssh_audit_event_type { - }; - typedef enum ssh_audit_event_type ssh_audit_event_t; - -+int listening_for_clients(void); -+ - void audit_connection_from(const char *, int); - void audit_event(ssh_audit_event_t); -+void audit_count_session_open(void); - void audit_session_open(struct logininfo *); - void audit_session_close(struct logininfo *); --void audit_run_command(const char *); -+int audit_run_command(const char *); -+void audit_end_command(int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(int, const char *, unsigned, char *, int); -+void audit_key(int, int *, const Key *); -+void audit_unsupported(int); -+void audit_kex(int, char *, char *, char *); -+void audit_unsupported_body(int); -+void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void audit_session_key_free(int ctos); -+void audit_session_key_free_body(int ctos, pid_t, uid_t); -+void audit_destroy_sensitive_data(const char *, pid_t, uid_t); -+void audit_generate_ephemeral_server_key(const char *); - - #endif /* _SSH_AUDIT_H */ -diff --git a/auditstub.c b/auditstub.c -new file mode 100644 -index 0000000..45817e0 ---- /dev/null -+++ b/auditstub.c -@@ -0,0 +1,50 @@ -+/* $Id: auditstub.c,v 1.1 jfch Exp $ */ -+ -+/* -+ * Copyright 2010 Red Hat, Inc. All rights reserved. -+ * Use is subject to license terms. -+ * -+ * 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. -+ * -+ * Red Hat author: Jan F. Chadima -+ */ -+ -+#include -+ -+void -+audit_unsupported(int n) -+{ -+} -+ -+void -+audit_kex(int ctos, char *enc, char *mac, char *comp) -+{ -+} -+ -+void -+audit_session_key_free(int ctos) -+{ -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+} -diff --git a/auth-rsa.c b/auth-rsa.c -index 5dad6c3..f225b0b 100644 ---- a/auth-rsa.c -+++ b/auth-rsa.c -@@ -93,7 +93,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) - { - u_char buf[32], mdbuf[16]; - struct ssh_digest_ctx *md; -- int len; -+ int len, rv; -+#ifdef SSH_AUDIT_EVENTS -+ char *fp; -+#endif - - /* don't allow short keys */ - if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -@@ -117,12 +120,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) - ssh_digest_free(md); - - /* Verify that the response is the original challenge. */ -- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { -- /* Wrong answer. */ -- return (0); -+ rv = timingsafe_bcmp(response, mdbuf, 16) == 0; -+ -+#ifdef SSH_AUDIT_EVENTS -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { -+ debug("unsuccessful audit"); -+ rv = 0; - } -- /* Correct answer. */ -- return (1); -+ free(fp); -+#endif -+ -+ return rv; - } - - /* -diff --git a/auth.c b/auth.c -index 420a85b..d613f8c 100644 ---- a/auth.c -+++ b/auth.c -@@ -628,9 +628,6 @@ getpwnamallow(const char *user) - record_failed_login(user, - get_canonical_hostname(options.use_dns), "ssh"); - #endif --#ifdef SSH_AUDIT_EVENTS -- audit_event(SSH_INVALID_USER); --#endif /* SSH_AUDIT_EVENTS */ - return (NULL); - } - if (!allowed_user(pw)) -diff --git a/auth.h b/auth.h -index 4605588..f9d191c 100644 ---- a/auth.h -+++ b/auth.h -@@ -186,6 +186,7 @@ void abandon_challenge_response(Authctxt *); - - char *expand_authorized_keys(const char *, struct passwd *pw); - char *authorized_principals_file(struct passwd *); -+int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); - - FILE *auth_openkeyfile(const char *, struct passwd *, int); - FILE *auth_openprincipals(const char *, struct passwd *, int); -@@ -203,6 +204,7 @@ Key *get_hostkey_private_by_type(int); - int get_hostkey_index(Key *); - int ssh1_session_key(BIGNUM *); - void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int); -+int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); - - /* debug messages during authentication */ - void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 95d678e..48aede4 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -137,7 +137,7 @@ userauth_hostbased(Authctxt *authctxt) - /* test for allowed key and correct signature */ - authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) - authenticated = 1; - -@@ -154,6 +154,18 @@ done: - return authenticated; - } - -+int -+hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(0, &rv, key); -+#endif -+ return rv; -+} -+ - /* return 1 if given hostkey is allowed */ - int - hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index cb0f931..6d1c872 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -160,7 +160,7 @@ userauth_pubkey(Authctxt *authctxt) - /* test for correct signature */ - authenticated = 0; - if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) - authenticated = 1; - buffer_free(&b); -@@ -231,6 +231,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) - free(extra); - } - -+int -+user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(1, &rv, key); -+#endif -+ return rv; -+} -+ - static int - match_principals_option(const char *principal_list, struct KeyCert *cert) - { -diff --git a/auth2.c b/auth2.c -index 426dcd6..436cd60 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) - } else { - logit("input_userauth_request: invalid user %s", user); - authctxt->pw = fakepw(); --#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(SSH_INVALID_USER)); --#endif - } - #ifdef USE_PAM - if (options.use_pam) -diff --git a/cipher.c b/cipher.c -index 53d9b4f..226e56d 100644 ---- a/cipher.c -+++ b/cipher.c -@@ -57,20 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_bf(void); - extern const EVP_CIPHER *evp_ssh1_3des(void); - extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); - --struct Cipher { -- char *name; -- int number; /* for ssh1 only */ -- u_int block_size; -- u_int key_len; -- u_int iv_len; /* defaults to block_size */ -- u_int auth_len; -- u_int discard_len; -- u_int flags; --#define CFLAG_CBC (1<<0) --#define CFLAG_CHACHAPOLY (1<<1) -- const EVP_CIPHER *(*evptype)(void); --}; -- - static const struct Cipher ciphers[] = { - { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, - { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, -diff --git a/cipher.h b/cipher.h -index 133d2e7..d41758e 100644 ---- a/cipher.h -+++ b/cipher.h -@@ -63,7 +63,20 @@ - typedef struct Cipher Cipher; - typedef struct CipherContext CipherContext; - --struct Cipher; -+struct Cipher { -+ char *name; -+ int number; /* for ssh1 only */ -+ u_int block_size; -+ u_int key_len; -+ u_int iv_len; /* defaults to block_size */ -+ u_int auth_len; -+ u_int discard_len; -+ u_int flags; -+#define CFLAG_CBC (1<<0) -+#define CFLAG_CHACHAPOLY (1<<1) -+ const EVP_CIPHER *(*evptype)(void); -+}; -+ - struct CipherContext { - int plaintext; - int encrypt; -diff --git a/kex.c b/kex.c -index bce2ab8..bc3e53e 100644 ---- a/kex.c -+++ b/kex.c -@@ -50,6 +50,7 @@ - #include "monitor.h" - #include "roaming.h" - #include "digest.h" -+#include "audit.h" - - #ifdef GSSAPI - #include "ssh-gss.h" -@@ -366,9 +367,13 @@ static void - choose_enc(Enc *enc, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(0); -+#endif - fatal("no matching cipher found: client %s server %s", - client, server); -+ } - if ((enc->cipher = cipher_by_name(name)) == NULL) - fatal("matching cipher is not supported: %s", name); - enc->name = name; -@@ -384,9 +389,13 @@ static void - choose_mac(Mac *mac, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(1); -+#endif - fatal("no matching mac found: client %s server %s", - client, server); -+ } - if (mac_setup(mac, name) < 0) - fatal("unsupported mac %s", name); - /* truncate the key */ -@@ -401,8 +410,12 @@ static void - choose_comp(Comp *comp, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(2); -+#endif - fatal("no matching comp found: client %s server %s", client, server); -+ } - if (strcmp(name, "zlib@openssh.com") == 0) { - comp->type = COMP_DELAYED; - } else if (strcmp(name, "zlib") == 0) { -@@ -517,6 +530,9 @@ kex_choose_conf(Kex *kex) - newkeys->enc.name, - authlen == 0 ? newkeys->mac.name : "", - newkeys->comp.name); -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); -+#endif - } - choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], -@@ -702,3 +718,34 @@ dump_digest(char *msg, u_char *digest, int len) - fprintf(stderr, "\n"); - } - #endif -+ -+static void -+enc_destroy(Enc *enc) -+{ -+ if (enc == NULL) -+ return; -+ -+ if (enc->key) { -+ memset(enc->key, 0, enc->key_len); -+ free(enc->key); -+ } -+ -+ if (enc->iv) { -+ memset(enc->iv, 0, enc->block_size); -+ free(enc->iv); -+ } -+ -+ memset(enc, 0, sizeof(*enc)); -+} -+ -+void -+newkeys_destroy(Newkeys *newkeys) -+{ -+ if (newkeys == NULL) -+ return; -+ -+ enc_destroy(&newkeys->enc); -+ mac_destroy(&newkeys->mac); -+ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); -+} -+ -diff --git a/kex.h b/kex.h -index 313bb51..c643250 100644 ---- a/kex.h -+++ b/kex.h -@@ -182,6 +182,8 @@ void kexgss_client(Kex *); - void kexgss_server(Kex *); - #endif - -+void newkeys_destroy(Newkeys *newkeys); -+ - void - kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, - BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); -diff --git a/key.c b/key.c -index 900b9e3..62f3edb 100644 ---- a/key.c -+++ b/key.c -@@ -1925,6 +1925,33 @@ key_demote(const Key *k) - } - - int -+key_is_private(const Key *k) -+{ -+ switch (k->type) { -+ case KEY_RSA_CERT_V00: -+ case KEY_RSA_CERT: -+ case KEY_RSA1: -+ case KEY_RSA: -+ return k->rsa->d != NULL; -+ case KEY_DSA_CERT_V00: -+ case KEY_DSA_CERT: -+ case KEY_DSA: -+ return k->dsa->priv_key != NULL; -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ fatal("key_is_private: bad key type %d", k->type); -+ return 1; -+ } -+} -+ -+int - key_is_cert(const Key *k) - { - if (k == NULL) -diff --git a/key.h b/key.h -index d51ed81..8f61605 100644 ---- a/key.h -+++ b/key.h -@@ -118,6 +118,7 @@ Key *key_generate(int, u_int); - Key *key_from_private(const Key *); - int key_type_from_name(char *); - int key_is_cert(const Key *); -+int key_is_private(const Key *k); - int key_type_is_cert(int); - int key_type_plain(int); - int key_to_certified(Key *, int); -diff --git a/mac.c b/mac.c -index 0977572..9388af4 100644 ---- a/mac.c -+++ b/mac.c -@@ -222,6 +222,20 @@ mac_clear(Mac *mac) - mac->umac_ctx = NULL; - } - -+void -+mac_destroy(Mac *mac) -+{ -+ if (mac == NULL) -+ return; -+ -+ if (mac->key) { -+ memset(mac->key, 0, mac->key_len); -+ free(mac->key); -+ } -+ -+ memset(mac, 0, sizeof(*mac)); -+} -+ - /* XXX copied from ciphers_valid */ - #define MAC_SEP "," - int -diff --git a/mac.h b/mac.h -index fbe18c4..7dc7f43 100644 ---- a/mac.h -+++ b/mac.h -@@ -29,3 +29,4 @@ int mac_setup(Mac *, char *); - int mac_init(Mac *); - u_char *mac_compute(Mac *, u_int32_t, u_char *, int); - void mac_clear(Mac *); -+void mac_destroy(Mac *); -diff --git a/monitor.c b/monitor.c -index 8b18086..5a65114 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -97,6 +97,7 @@ - #include "ssh2.h" - #include "roaming.h" - #include "authfd.h" -+#include "audit.h" - - #ifdef GSSAPI - static Gssctxt *gsscontext = NULL; -@@ -113,6 +114,8 @@ extern Buffer auth_debug; - extern int auth_debug_init; - extern Buffer loginmsg; - -+extern void destroy_sensitive_data(int); -+ - /* State exported from the child */ - - struct { -@@ -185,6 +188,11 @@ int mm_answer_gss_updatecreds(int, Buffer *); - #ifdef SSH_AUDIT_EVENTS - int mm_answer_audit_event(int, Buffer *); - int mm_answer_audit_command(int, Buffer *); -+int mm_answer_audit_end_command(int, Buffer *); -+int mm_answer_audit_unsupported_body(int, Buffer *); -+int mm_answer_audit_kex_body(int, Buffer *); -+int mm_answer_audit_session_key_free_body(int, Buffer *); -+int mm_answer_audit_server_key_free(int, Buffer *); - #endif - - static int monitor_read_log(struct monitor *); -@@ -239,6 +247,10 @@ struct mon_table mon_dispatch_proto20[] = { - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - #ifdef BSD_AUTH - {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -274,6 +286,11 @@ struct mon_table mon_dispatch_postauth20[] = { - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -305,6 +322,10 @@ struct mon_table mon_dispatch_proto15[] = { - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -316,6 +337,11 @@ struct mon_table mon_dispatch_postauth15[] = { - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -1393,9 +1419,11 @@ mm_answer_keyverify(int sock, Buffer *m) - Key *key; - u_char *signature, *data, *blob; - u_int signaturelen, datalen, bloblen; -+ int type = 0; - int verified = 0; - int valid_data = 0; - -+ type = buffer_get_int(m); - blob = buffer_get_string(m, &bloblen); - signature = buffer_get_string(m, &signaturelen); - data = buffer_get_string(m, &datalen); -@@ -1403,6 +1431,8 @@ mm_answer_keyverify(int sock, Buffer *m) - if (hostbased_cuser == NULL || hostbased_chost == NULL || - !monitor_allowed_key(blob, bloblen)) - fatal("%s: bad key, not previously allowed", __func__); -+ if (type != key_blobtype) -+ fatal("%s: bad key type", __func__); - - key = key_from_blob(blob, bloblen); - if (key == NULL) -@@ -1423,7 +1453,17 @@ mm_answer_keyverify(int sock, Buffer *m) - if (!valid_data) - fatal("%s: bad signature data blob", __func__); - -- verified = key_verify(key, signature, signaturelen, data, datalen); -+ switch (key_blobtype) { -+ case MM_USERKEY: -+ verified = user_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ case MM_HOSTKEY: -+ verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ default: -+ verified = 0; -+ break; -+ } - debug3("%s: key %p signature %s", - __func__, key, (verified == 1) ? "verified" : "unverified"); - -@@ -1476,6 +1516,12 @@ mm_session_close(Session *s) - debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); - session_pty_cleanup2(s); - } -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL) { -+ debug3("%s: command %d", __func__, s->command_handle); -+ session_end_command2(s); -+ } -+#endif - session_unused(s->self); - } - -@@ -1756,6 +1802,8 @@ mm_answer_term(int sock, Buffer *req) - sshpam_cleanup(); - #endif - -+ destroy_sensitive_data(0); -+ - while (waitpid(pmonitor->m_pid, &status, 0) == -1) - if (errno != EINTR) - exit(1); -@@ -1798,11 +1846,43 @@ mm_answer_audit_command(int socket, Buffer *m) - { - u_int len; - char *cmd; -+ Session *s; - - debug3("%s entering", __func__); - cmd = buffer_get_string(m, &len); -+ - /* sanity check command, if so how? */ -- audit_run_command(cmd); -+ s = session_new(); -+ if (s == NULL) -+ fatal("%s: error allocating a session", __func__); -+ s->command = cmd; -+ s->command_handle = audit_run_command(cmd); -+ -+ buffer_clear(m); -+ buffer_put_int(m, s->self); -+ -+ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); -+ -+ return (0); -+} -+ -+int -+mm_answer_audit_end_command(int socket, Buffer *m) -+{ -+ int handle; -+ u_int len; -+ char *cmd; -+ Session *s; -+ -+ debug3("%s entering", __func__); -+ handle = buffer_get_int(m); -+ cmd = buffer_get_string(m, &len); -+ -+ s = session_by_id(handle); -+ if (s == NULL || s->ttyfd != -1 || s->command == NULL || -+ strcmp(s->command, cmd) != 0) -+ fatal("%s: invalid handle", __func__); -+ mm_session_close(s); - free(cmd); - return (0); - } -@@ -1946,11 +2026,13 @@ mm_get_keystate(struct monitor *pmonitor) - - blob = buffer_get_string(&m, &bloblen); - current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - debug3("%s: Waiting for second key", __func__); - blob = buffer_get_string(&m, &bloblen); - current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - /* Now get sequence numbers for the packets */ -@@ -1996,6 +2078,21 @@ mm_get_keystate(struct monitor *pmonitor) - } - - buffer_free(&m); -+ -+#ifdef SSH_AUDIT_EVENTS -+ if (compat20) { -+ buffer_init(&m); -+ mm_request_receive_expect(pmonitor->m_sendfd, -+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); -+ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m); -+ buffer_free(&m); -+ } -+#endif -+ -+ /* Drain any buffered messages from the child */ -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) -+ ; -+ - } - - -@@ -2277,3 +2374,85 @@ mm_answer_gss_updatecreds(int socket, Buffer *m) { - - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+int -+mm_answer_audit_unsupported_body(int sock, Buffer *m) -+{ -+ int what; -+ -+ what = buffer_get_int(m); -+ -+ audit_unsupported_body(what); -+ -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_kex_body(int sock, Buffer *m) -+{ -+ int ctos, len; -+ char *cipher, *mac, *compress; -+ pid_t pid; -+ uid_t uid; -+ -+ ctos = buffer_get_int(m); -+ cipher = buffer_get_string(m, &len); -+ mac = buffer_get_string(m, &len); -+ compress = buffer_get_string(m, &len); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_kex_body(ctos, cipher, mac, compress, pid, uid); -+ -+ free(cipher); -+ free(mac); -+ free(compress); -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_session_key_free_body(int sock, Buffer *m) -+{ -+ int ctos; -+ pid_t pid; -+ uid_t uid; -+ -+ ctos = buffer_get_int(m); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_session_key_free_body(ctos, pid, uid); -+ -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_server_key_free(int sock, Buffer *m) -+{ -+ int len; -+ char *fp; -+ pid_t pid; -+ uid_t uid; -+ -+ fp = buffer_get_string(m, &len); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_destroy_sensitive_data(fp, pid, uid); -+ -+ free(fp); -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m); -+ return 0; -+} -+#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor.h b/monitor.h -index ff79fbb..6dfb234 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -69,7 +69,13 @@ enum monitor_reqtype { - MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, - MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, - MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, -- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, -+ MONITOR_REQ_AUDIT_EVENT = 112, -+ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, -+ MONITOR_REQ_AUDIT_END_COMMAND = 116, -+ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, -+ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, -+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, -+ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125 - - }; - -diff --git a/monitor_wrap.c b/monitor_wrap.c -index d1e1caa..6df236a 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -450,7 +450,7 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) - */ - - int --mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - { - Buffer m; - u_char *blob; -@@ -464,6 +464,7 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - return (0); - - buffer_init(&m); -+ buffer_put_int(&m, type); - buffer_put_string(&m, blob, len); - buffer_put_string(&m, sig, siglen); - buffer_put_string(&m, data, datalen); -@@ -481,6 +482,19 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - return (verified); - } - -+int -+mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); -+} -+ -+int -+mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); -+} -+ -+ - /* Export key state after authentication */ - Newkeys * - mm_newkeys_from_blob(u_char *blob, int blen) -@@ -659,12 +673,14 @@ mm_send_keystate(struct monitor *monitor) - fatal("%s: conversion of newkeys failed", __func__); - - buffer_put_string(&m, blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) - fatal("%s: conversion of newkeys failed", __func__); - - buffer_put_string(&m, blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes); -@@ -1208,10 +1224,11 @@ mm_audit_event(ssh_audit_event_t event) - buffer_free(&m); - } - --void -+int - mm_audit_run_command(const char *command) - { - Buffer m; -+ int handle; - - debug3("%s entering command %s", __func__, command); - -@@ -1219,6 +1236,26 @@ mm_audit_run_command(const char *command) - buffer_put_cstring(&m, command); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); -+ -+ handle = buffer_get_int(&m); -+ buffer_free(&m); -+ -+ return (handle); -+} -+ -+void -+mm_audit_end_command(int handle, const char *command) -+{ -+ Buffer m; -+ -+ debug3("%s entering command %s", __func__, command); -+ -+ buffer_init(&m); -+ buffer_put_int(&m, handle); -+ buffer_put_cstring(&m, command); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); - buffer_free(&m); - } - #endif /* SSH_AUDIT_EVENTS */ -@@ -1354,3 +1391,71 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) - - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+void -+mm_audit_unsupported_body(int what) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, what); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, -+ uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_cstring(&m, cipher); -+ buffer_put_cstring(&m, (mac ? mac : "")); -+ buffer_put_cstring(&m, compress); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, -+ &m); -+ buffer_free(&m); -+} -+ -+void -+mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_cstring(&m, fp); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, -+ &m); -+ buffer_free(&m); -+} -+#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 93929e0..4cf0c78 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char *, char *, Key *); - int mm_user_key_allowed(struct passwd *, Key *); - int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); - int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); --int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); -+int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); -+int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); - int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); - int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); - BIGNUM *mm_auth_rsa_generate_challenge(Key *); -@@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *); - #ifdef SSH_AUDIT_EVENTS - #include "audit.h" - void mm_audit_event(ssh_audit_event_t); --void mm_audit_run_command(const char *); -+int mm_audit_run_command(const char *); -+void mm_audit_end_command(int, const char *); -+void mm_audit_unsupported_body(int); -+void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void mm_audit_session_key_free_body(int, pid_t, uid_t); -+void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); - #endif - - struct Session; -diff --git a/packet.c b/packet.c -index 660a9fc..f5b122b 100644 ---- a/packet.c -+++ b/packet.c -@@ -61,6 +61,7 @@ - #include - - #include "xmalloc.h" -+#include "audit.h" - #include "buffer.h" - #include "packet.h" - #include "crc32.h" -@@ -476,6 +477,13 @@ packet_get_connection_out(void) - return active_state->connection_out; - } - -+static int -+packet_state_has_keys (const struct session_state *state) -+{ -+ return state != NULL && -+ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); -+} -+ - /* Closes the connection and clears and frees internal data structures. */ - - void -@@ -484,13 +492,6 @@ packet_close(void) - if (!active_state->initialized) - return; - active_state->initialized = 0; -- if (active_state->connection_in == active_state->connection_out) { -- shutdown(active_state->connection_out, SHUT_RDWR); -- close(active_state->connection_out); -- } else { -- close(active_state->connection_in); -- close(active_state->connection_out); -- } - buffer_free(&active_state->input); - buffer_free(&active_state->output); - buffer_free(&active_state->outgoing_packet); -@@ -499,8 +500,18 @@ packet_close(void) - buffer_free(&active_state->compression_buffer); - buffer_compress_uninit(); - } -- cipher_cleanup(&active_state->send_context); -- cipher_cleanup(&active_state->receive_context); -+ if (packet_state_has_keys(active_state)) { -+ cipher_cleanup(&active_state->send_context); -+ cipher_cleanup(&active_state->receive_context); -+ audit_session_key_free(2); -+ } -+ if (active_state->connection_in == active_state->connection_out) { -+ shutdown(active_state->connection_out, SHUT_RDWR); -+ close(active_state->connection_out); -+ } else { -+ close(active_state->connection_in); -+ close(active_state->connection_out); -+ } - } - - /* Sets remote side protocol flags. */ -@@ -736,6 +747,25 @@ packet_send1(void) - */ - } - -+static void -+newkeys_destroy_and_free(Newkeys *newkeys) -+{ -+ if (newkeys == NULL) -+ return; -+ -+ free(newkeys->enc.name); -+ -+ if (newkeys->mac.enabled) { -+ mac_clear(&newkeys->mac); -+ free(newkeys->mac.name); -+ } -+ -+ free(newkeys->comp.name); -+ -+ newkeys_destroy(newkeys); -+ free(newkeys); -+} -+ - void - set_newkeys(int mode) - { -@@ -761,6 +791,7 @@ set_newkeys(int mode) - } - if (active_state->newkeys[mode] != NULL) { - debug("set_newkeys: rekeying"); -+ audit_session_key_free(mode); - cipher_cleanup(cc); - enc = &active_state->newkeys[mode]->enc; - mac = &active_state->newkeys[mode]->mac; -@@ -2011,6 +2042,47 @@ packet_get_newkeys(int mode) - return (void *)active_state->newkeys[mode]; - } - -+static void -+packet_destroy_state(struct session_state *state) -+{ -+ if (state == NULL) -+ return; -+ -+ cipher_cleanup(&state->receive_context); -+ cipher_cleanup(&state->send_context); -+ -+ buffer_free(&state->input); -+ buffer_free(&state->output); -+ buffer_free(&state->outgoing_packet); -+ buffer_free(&state->incoming_packet); -+ buffer_free(&state->compression_buffer); -+ newkeys_destroy_and_free(state->newkeys[MODE_IN]); -+ state->newkeys[MODE_IN] = NULL; -+ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); -+ state->newkeys[MODE_OUT] = NULL; -+ mac_destroy(state->packet_discard_mac); -+// TAILQ_HEAD(, packet) outgoing; -+// memset(state, 0, sizeof(state)); -+} -+ -+void -+packet_destroy_all(int audit_it, int privsep) -+{ -+ if (audit_it) -+ audit_it = packet_state_has_keys (active_state) || -+ packet_state_has_keys (backup_state); -+ packet_destroy_state(active_state); -+ packet_destroy_state(backup_state); -+ if (audit_it) { -+#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ audit_session_key_free(2); -+ else -+ audit_session_key_free_body(2, getpid(), getuid()); -+#endif -+ } -+} -+ - /* - * Save the state for the real connection, and use a separate state when - * resuming a suspended connection. -@@ -2018,18 +2090,12 @@ packet_get_newkeys(int mode) - void - packet_backup_state(void) - { -- struct session_state *tmp; -- - close(active_state->connection_in); - active_state->connection_in = -1; - close(active_state->connection_out); - active_state->connection_out = -1; -- if (backup_state) -- tmp = backup_state; -- else -- tmp = alloc_session_state(); - backup_state = active_state; -- active_state = tmp; -+ active_state = alloc_session_state(); - } - - /* -@@ -2046,9 +2112,7 @@ packet_restore_state(void) - backup_state = active_state; - active_state = tmp; - active_state->connection_in = backup_state->connection_in; -- backup_state->connection_in = -1; - active_state->connection_out = backup_state->connection_out; -- backup_state->connection_out = -1; - len = buffer_len(&backup_state->input); - if (len > 0) { - buf = buffer_ptr(&backup_state->input); -@@ -2056,4 +2120,10 @@ packet_restore_state(void) - buffer_clear(&backup_state->input); - add_recv_bytes(len); - } -+ backup_state->connection_in = -1; -+ backup_state->connection_out = -1; -+ packet_destroy_state(backup_state); -+ free(backup_state); -+ backup_state = NULL; - } -+ -diff --git a/packet.h b/packet.h -index f8edf85..c36c812 100644 ---- a/packet.h -+++ b/packet.h -@@ -124,4 +124,5 @@ void packet_restore_state(void); - void *packet_get_input(void); - void *packet_get_output(void); - -+void packet_destroy_all(int, int); - #endif /* PACKET_H */ -diff --git a/session.c b/session.c -index df43592..b186ca1 100644 ---- a/session.c -+++ b/session.c -@@ -138,7 +138,7 @@ extern int log_stderr; - extern int debug_flag; - extern u_int utmp_len; - extern int startup_pipe; --extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(int); - extern Buffer loginmsg; - - /* original command from peer. */ -@@ -746,6 +746,14 @@ do_exec_pty(Session *s, const char *command) - /* Parent. Close the slave side of the pseudo tty. */ - close(ttyfd); - -+#ifndef HAVE_OSF_SIA -+ /* do_login in the child did not affect state in this process, -+ compensate. From an architectural standpoint, this is extremely -+ ugly. */ -+ if (!(options.use_login && command == NULL)) -+ audit_count_session_open(); -+#endif -+ - /* Enter interactive session. */ - s->ptymaster = ptymaster; - packet_set_interactive(1, -@@ -863,15 +871,19 @@ do_exec(Session *s, const char *command) - get_remote_port()); - - #ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL || s->command_handle != -1) -+ fatal("do_exec: command already set"); - if (command != NULL) -- PRIVSEP(audit_run_command(command)); -+ s->command = xstrdup(command); - else if (s->ttyfd == -1) { - char *shell = s->pw->pw_shell; - - if (shell[0] == '\0') /* empty shell means /bin/sh */ - shell =_PATH_BSHELL; -- PRIVSEP(audit_run_command(shell)); -+ s->command = xstrdup(shell); - } -+ if (s->command != NULL) -+ s->command_handle = PRIVSEP(audit_run_command(s->command)); - #endif - if (s->ttyfd != -1) - ret = do_exec_pty(s, command); -@@ -1708,7 +1720,10 @@ do_child(Session *s, const char *command) - int r = 0; - - /* remove hostkey from the child's memory */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(1); -+ /* Don't audit this - both us and the parent would be talking to the -+ monitor over a single socket, with no synchronization. */ -+ packet_destroy_all(0, 1); - - /* Force a password change */ - if (s->authctxt->force_pwchange) { -@@ -1933,6 +1948,7 @@ session_unused(int id) - sessions[id].ttyfd = -1; - sessions[id].ptymaster = -1; - sessions[id].x11_chanids = NULL; -+ sessions[id].command_handle = -1; - sessions[id].next_unused = sessions_first_unused; - sessions_first_unused = id; - } -@@ -2015,6 +2031,19 @@ session_open(Authctxt *authctxt, int chanid) - } - - Session * -+session_by_id(int id) -+{ -+ if (id >= 0 && id < sessions_nalloc) { -+ Session *s = &sessions[id]; -+ if (s->used) -+ return s; -+ } -+ debug("session_by_id: unknown id %d", id); -+ session_dump(); -+ return NULL; -+} -+ -+Session * - session_by_tty(char *tty) - { - int i; -@@ -2531,6 +2560,30 @@ session_exit_message(Session *s, int status) - chan_write_failed(c); - } - -+#ifdef SSH_AUDIT_EVENTS -+void -+session_end_command2(Session *s) -+{ -+ if (s->command != NULL) { -+ audit_end_command(s->command_handle, s->command); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+ -+static void -+session_end_command(Session *s) -+{ -+ if (s->command != NULL) { -+ PRIVSEP(audit_end_command(s->command_handle, s->command)); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+#endif -+ - void - session_close(Session *s) - { -@@ -2539,6 +2592,10 @@ session_close(Session *s) - debug("session_close: session %d pid %ld", s->self, (long)s->pid); - if (s->ttyfd != -1) - session_pty_cleanup(s); -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command) -+ session_end_command(s); -+#endif - free(s->term); - free(s->display); - free(s->x11_chanids); -@@ -2753,6 +2810,15 @@ do_authenticated2(Authctxt *authctxt) - server_loop2(authctxt); - } - -+static void -+do_cleanup_one_session(Session *s) -+{ -+ session_pty_cleanup2(s); -+#ifdef SSH_AUDIT_EVENTS -+ session_end_command2(s); -+#endif -+} -+ - void - do_cleanup(Authctxt *authctxt) - { -@@ -2801,5 +2867,5 @@ do_cleanup(Authctxt *authctxt) - * or if running in monitor. - */ - if (!use_privsep || mm_is_monitor()) -- session_destroy_all(session_pty_cleanup2); -+ session_destroy_all(do_cleanup_one_session); - } -diff --git a/session.h b/session.h -index 6a2f35e..e9b312e 100644 ---- a/session.h -+++ b/session.h -@@ -61,6 +61,12 @@ struct Session { - char *name; - char *val; - } *env; -+ -+ /* exec */ -+#ifdef SSH_AUDIT_EVENTS -+ int command_handle; -+ char *command; -+#endif - }; - - void do_authenticated(Authctxt *); -@@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); - void session_close_by_channel(int, void *); - void session_destroy_all(void (*)(Session *)); - void session_pty_cleanup2(Session *); -+void session_end_command2(Session *); - - Session *session_new(void); -+Session *session_by_id(int); - Session *session_by_tty(char *); - void session_close(Session *); - void do_setusercontext(struct passwd *); -diff --git a/sshd.c b/sshd.c -index 8a0740a..2813aa2 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -119,6 +119,7 @@ - #endif - #include "monitor_wrap.h" - #include "roaming.h" -+#include "audit.h" - #include "ssh-sandbox.h" - #include "version.h" - -@@ -264,7 +265,7 @@ Buffer loginmsg; - struct passwd *privsep_pw = NULL; - - /* Prototypes for various functions defined later in this file. */ --void destroy_sensitive_data(void); -+void destroy_sensitive_data(int); - void demote_sensitive_data(void); - - static void do_ssh1_kex(void); -@@ -283,6 +284,15 @@ close_listen_socks(void) - num_listen_socks = -1; - } - -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) -+{ -+ return num_listen_socks > 0; -+} -+ - static void - close_startup_pipes(void) - { -@@ -562,22 +572,45 @@ sshd_exchange_identification(int sock_in, int sock_out) - } - } - --/* Destroy the host and server keys. They will no longer be needed. */ -+/* -+ * Destroy the host and server keys. They will no longer be needed. Careful, -+ * this can be called from cleanup_exit() - i.e. from just about anywhere. -+ */ - void --destroy_sensitive_data(void) -+destroy_sensitive_data(int privsep) - { - int i; -+ pid_t pid; -+ uid_t uid; - - if (sensitive_data.server_key) { - key_free(sensitive_data.server_key); - sensitive_data.server_key = NULL; - } -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX); -+ else -+ fp = NULL; - key_free(sensitive_data.host_keys[i]); - sensitive_data.host_keys[i] = NULL; -+ if (fp != NULL) { -+ if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(fp, -+ pid, uid)); -+ else -+ audit_destroy_sensitive_data(fp, -+ pid, uid); -+ free(fp); -+ } - } -- if (sensitive_data.host_certificates[i]) { -+ if (sensitive_data.host_certificates -+ && sensitive_data.host_certificates[i]) { - key_free(sensitive_data.host_certificates[i]); - sensitive_data.host_certificates[i] = NULL; - } -@@ -591,6 +624,8 @@ void - demote_sensitive_data(void) - { - Key *tmp; -+ pid_t pid; -+ uid_t uid; - int i; - - if (sensitive_data.server_key) { -@@ -599,13 +634,25 @@ demote_sensitive_data(void) - sensitive_data.server_key = tmp; - } - -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX); -+ else -+ fp = NULL; - tmp = key_demote(sensitive_data.host_keys[i]); - key_free(sensitive_data.host_keys[i]); - sensitive_data.host_keys[i] = tmp; - if (tmp->type == KEY_RSA1) - sensitive_data.ssh1_host_key = tmp; -+ if (fp != NULL) { -+ audit_destroy_sensitive_data(fp, pid, uid); -+ free(fp); -+ } - } - /* Certs do not need demotion */ - } -@@ -675,7 +722,7 @@ privsep_preauth(Authctxt *authctxt) - - if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(pmonitor); -- pid = fork(); -+ pmonitor->m_pid = pid = fork(); - if (pid == -1) { - fatal("fork of unprivileged child failed"); - } else if (pid != 0) { -@@ -729,6 +776,8 @@ privsep_preauth(Authctxt *authctxt) - } - } - -+extern Newkeys *current_keys[]; -+ - static void - privsep_postauth(Authctxt *authctxt) - { -@@ -753,6 +802,10 @@ privsep_postauth(Authctxt *authctxt) - else if (pmonitor->m_pid != 0) { - verbose("User child is on pid %ld", (long)pmonitor->m_pid); - buffer_clear(&loginmsg); -+ newkeys_destroy(current_keys[MODE_OUT]); -+ newkeys_destroy(current_keys[MODE_IN]); -+ audit_session_key_free_body(2, getpid(), getuid()); -+ packet_destroy_all(0, 0); - monitor_child_postauth(pmonitor); - - /* NEVERREACHED */ -@@ -1211,6 +1264,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) - if (received_sigterm) { - logit("Received signal %d; terminating.", - (int) received_sigterm); -+ destroy_sensitive_data(0); - close_listen_socks(); - unlink(options.pid_file); - exit(received_sigterm == SIGTERM ? 0 : 255); -@@ -2134,6 +2188,7 @@ main(int ac, char **av) - */ - if (use_privsep) { - mm_send_keystate(pmonitor); -+ packet_destroy_all(1, 1); - exit(0); - } - -@@ -2179,7 +2234,7 @@ main(int ac, char **av) - privsep_postauth(authctxt); - /* the monitor process [priv] will not return */ - if (!compat20) -- destroy_sensitive_data(); -+ destroy_sensitive_data(0); - } - - packet_set_timeout(options.client_alive_interval, -@@ -2189,6 +2244,9 @@ main(int ac, char **av) - do_authenticated(authctxt); - - /* The connection has been terminated. */ -+ packet_destroy_all(1, 1); -+ destroy_sensitive_data(1); -+ - packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); - packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); - verbose("Transferred: sent %llu, received %llu bytes", -@@ -2346,6 +2404,10 @@ do_ssh1_kex(void) - if (cookie[i] != packet_get_char()) - packet_disconnect("IP Spoofing check bytes do not match."); - -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(2, cipher_name(cipher_type), "crc", "none"); -+#endif -+ - debug("Encryption type: %.200s", cipher_name(cipher_type)); - - /* Get the encrypted integer. */ -@@ -2418,7 +2480,7 @@ do_ssh1_kex(void) - session_id[i] = session_key[i] ^ session_key[i + 16]; - } - /* Destroy the private and public keys. No longer. */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(0); - - if (use_privsep) - mm_ssh1_session_id(session_id); -@@ -2584,6 +2646,16 @@ do_ssh2_kex(void) - void - cleanup_exit(int i) - { -+ static int in_cleanup = 0; -+ int is_privsep_child; -+ -+ /* cleanup_exit can be called at the very least from the privsep -+ wrappers used for auditing. Make sure we don't recurse -+ indefinitely. */ -+ if (in_cleanup) -+ _exit(i); -+ in_cleanup = 1; -+ - if (the_authctxt) { - do_cleanup(the_authctxt); - if (use_privsep && privsep_is_preauth && pmonitor->m_pid > 1) { -@@ -2594,9 +2666,14 @@ cleanup_exit(int i) - pmonitor->m_pid, strerror(errno)); - } - } -+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL) -+ destroy_sensitive_data(is_privsep_child); -+ packet_destroy_all(1, is_privsep_child); - #ifdef SSH_AUDIT_EVENTS - /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (!use_privsep || mm_is_monitor()) -+ if ((the_authctxt == NULL || !the_authctxt->authenticated) && -+ (!use_privsep || mm_is_monitor())) - audit_event(SSH_CONNECTION_ABANDON); - #endif - _exit(i); diff --git a/openssh-6.6p1-ctr-cavstest.patch b/openssh-6.6p1-ctr-cavstest.patch index 1997fa6..c752d62 100644 --- a/openssh-6.6p1-ctr-cavstest.patch +++ b/openssh-6.6p1-ctr-cavstest.patch @@ -1,5 +1,5 @@ diff --git a/Makefile.in b/Makefile.in -index 4ab6717..581b121 100644 +index b225217..bbc3034 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,6 +28,7 @@ SSH_KEYSIGN=$(libexecdir)/ssh-keysign @@ -10,16 +10,16 @@ index 4ab6717..581b121 100644 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ +@@ -66,7 +67,7 @@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ 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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -180,6 +181,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o + LIBOPENSSH_OBJS=\ + ssherr.o \ +@@ -190,6 +191,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o $(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(SSHLIBS) @@ -29,7 +29,7 @@ index 4ab6717..581b121 100644 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) -@@ -288,6 +292,7 @@ install-files: +@@ -310,6 +314,7 @@ install-files: $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ fi $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) diff --git a/openssh-6.6p1-entropy.patch b/openssh-6.6p1-entropy.patch index 67bd30f..6076165 100644 --- a/openssh-6.6p1-entropy.patch +++ b/openssh-6.6p1-entropy.patch @@ -1,8 +1,8 @@ diff --git a/entropy.c b/entropy.c -index 2d483b3..b361a04 100644 +index 1e9d52a..d24e724 100644 --- a/entropy.c +++ b/entropy.c -@@ -234,6 +234,9 @@ seed_rng(void) +@@ -227,6 +227,9 @@ seed_rng(void) memset(buf, '\0', sizeof(buf)); #endif /* OPENSSL_PRNG_ONLY */ @@ -13,12 +13,12 @@ index 2d483b3..b361a04 100644 fatal("PRNG is not seeded"); } diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in -index b912dbe..9206337 100644 +index 843225d..041bbab 100644 --- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di - COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o + COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o -PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o +PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o @@ -27,7 +27,7 @@ index b912dbe..9206337 100644 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< diff --git a/openbsd-compat/port-linux-prng.c b/openbsd-compat/port-linux-prng.c new file mode 100644 -index 0000000..92a617c +index 0000000..da84bf2 --- /dev/null +++ b/openbsd-compat/port-linux-prng.c @@ -0,0 +1,59 @@ @@ -63,6 +63,7 @@ index 0000000..92a617c + +#include "log.h" +#include "xmalloc.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ +#include "servconf.h" +#include "port-linux.h" +#include "key.h" @@ -72,10 +73,9 @@ index 0000000..92a617c +void +linux_seed(void) +{ -+ int len; + char *env = getenv("SSH_USE_STRONG_RNG"); + char *random = "/dev/random"; -+ size_t ienv, randlen = 14; ++ size_t len, ienv, randlen = 14; + + if (!env || !strcmp(env, "0")) + random = "/dev/urandom"; @@ -91,7 +91,7 @@ index 0000000..92a617c + } +} diff --git a/ssh-add.0 b/ssh-add.0 -index ba43fee..0b2629a 100644 +index f16165a..17d22cf 100644 --- a/ssh-add.0 +++ b/ssh-add.0 @@ -82,6 +82,16 @@ ENVIRONMENT @@ -112,10 +112,10 @@ index ba43fee..0b2629a 100644 ~/.ssh/identity Contains the protocol version 1 RSA authentication identity of diff --git a/ssh-add.1 b/ssh-add.1 -index 4812448..16305bf 100644 +index 04d1840..db883a4 100644 --- a/ssh-add.1 +++ b/ssh-add.1 -@@ -161,6 +161,20 @@ to make this work.) +@@ -170,6 +170,20 @@ to make this work.) Identifies the path of a .Ux Ns -domain socket used to communicate with the agent. @@ -137,10 +137,10 @@ index 4812448..16305bf 100644 .Sh FILES .Bl -tag -width Ds diff --git a/ssh-agent.1 b/ssh-agent.1 -index 281ecbd..1a9a635 100644 +index d7e791b..7332f0d 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 -@@ -201,6 +201,24 @@ sockets used to contain the connection to the authentication agent. +@@ -189,6 +189,24 @@ sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El @@ -166,10 +166,10 @@ index 281ecbd..1a9a635 100644 .Xr ssh 1 , .Xr ssh-add 1 , diff --git a/ssh-keygen.1 b/ssh-keygen.1 -index 12e00d4..1b51a4a 100644 +index 276dacc..a09d9b1 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 -@@ -832,6 +832,24 @@ Contains Diffie-Hellman groups used for DH-GEX. +@@ -841,6 +841,24 @@ Contains Diffie-Hellman groups used for DH-GEX. The file format is described in .Xr moduli 5 . .El @@ -224,10 +224,10 @@ index 69d0829..02d79f8 100644 .Xr ssh 1 , .Xr ssh-keygen 1 , diff --git a/ssh.1 b/ssh.1 -index 929904b..f65e42f 100644 +index 4a476c2..410a04a 100644 --- a/ssh.1 +++ b/ssh.1 -@@ -1309,6 +1309,23 @@ For more information, see the +@@ -1299,6 +1299,23 @@ For more information, see the .Cm PermitUserEnvironment option in .Xr sshd_config 5 . @@ -252,10 +252,10 @@ index 929904b..f65e42f 100644 .Bl -tag -width Ds -compact .It Pa ~/.rhosts diff --git a/sshd.8 b/sshd.8 -index c2c237f..058d37a 100644 +index cb866b5..adcaaf9 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -951,6 +951,24 @@ concurrently for different ports, this contains the process ID of the one +@@ -945,6 +945,24 @@ concurrently for different ports, this contains the process ID of the one started last). The content of this file is not sensitive; it can be world-readable. .El diff --git a/openssh-6.6p1-fingerprint.patch b/openssh-6.6p1-fingerprint.patch deleted file mode 100644 index c5332fb..0000000 --- a/openssh-6.6p1-fingerprint.patch +++ /dev/null @@ -1,415 +0,0 @@ -diff --git a/auth.c b/auth.c -index 9a36f1d..420a85b 100644 ---- a/auth.c -+++ b/auth.c -@@ -685,9 +685,10 @@ auth_key_is_revoked(Key *key) - case 1: - revoked: - /* Key revoked */ -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_selected_fingerprint(key, SSH_FP_HEX); - error("WARNING: authentication attempt with a revoked " -- "%s key %s ", key_type(key), key_fp); -+ "%s key %s%s ", key_type(key), -+ key_fingerprint_prefix(), key_fp); - free(key_fp); - return 1; - } -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 488008f..eca0069 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -206,16 +206,18 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, - - if (host_status == HOST_OK) { - if (key_is_cert(key)) { -- fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key->cert->signature_key, -+ SSH_FP_HEX); - verbose("Accepted certificate ID \"%s\" signed by " -- "%s CA %s from %s@%s", key->cert->key_id, -- key_type(key->cert->signature_key), fp, -+ "%s CA %s%s from %s@%s", key->cert->key_id, -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), fp, - cuser, lookup); - } else { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- verbose("Accepted %s public key %s from %s@%s", -- key_type(key), fp, cuser, lookup); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ verbose("Accepted %s public key %s%s from %s@%s", -+ key_type(key), key_fingerprint_prefix(), -+ fp, cuser, lookup); - } - free(fp); - } -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 0fd27bb..749b11a 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -365,10 +365,10 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) - continue; - if (!key_is_cert_authority) - continue; -- fp = key_fingerprint(found, SSH_FP_MD5, -- SSH_FP_HEX); -- debug("matching CA found: file %s, line %lu, %s %s", -- file, linenum, key_type(found), fp); -+ fp = key_selected_fingerprint(found, SSH_FP_HEX); -+ debug("matching CA found: file %s, line %lu, %s %s%s", -+ file, linenum, key_type(found), -+ key_fingerprint_prefix(), fp); - /* - * If the user has specified a list of principals as - * a key option, then prefer that list to matching -@@ -406,9 +406,9 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) - if (key_is_cert_authority) - continue; - found_key = 1; -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -- debug("matching key found: file %s, line %lu %s %s", -- file, linenum, key_type(found), fp); -+ fp = key_selected_fingerprint(found, SSH_FP_HEX); -+ verbose("Found matching %s key: %s%s", -+ key_type(found), key_fingerprint_prefix(), fp); - free(fp); - break; - } -@@ -431,13 +431,13 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) - if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) - return 0; - -- ca_fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX); - - if (key_in_file(key->cert->signature_key, - options.trusted_user_ca_keys, 1) != 1) { -- debug2("%s: CA %s %s is not listed in %s", __func__, -- key_type(key->cert->signature_key), ca_fp, -+ debug2("%s: CA %s%s %s is not listed in %s", __func__, -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), ca_fp, - options.trusted_user_ca_keys); - goto out; - } -diff --git a/key.c b/key.c -index 168e1b7..eb98ea8 100644 ---- a/key.c -+++ b/key.c -@@ -628,6 +628,34 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) - return retval; - } - -+enum fp_type -+key_fingerprint_selection(void) -+{ -+ static enum fp_type rv; -+ static char rv_defined = 0; -+ char *env; -+ -+ if (!rv_defined) { -+ env = getenv("SSH_FINGERPRINT_TYPE"); -+ rv = (env && !strcmp (env, "sha")) ? -+ SSH_FP_SHA1 : SSH_FP_MD5; -+ rv_defined = 1; -+ } -+ return rv; -+} -+ -+char * -+key_selected_fingerprint(Key *k, enum fp_rep dgst_rep) -+{ -+ return key_fingerprint(k, key_fingerprint_selection(), dgst_rep); -+} -+ -+char * -+key_fingerprint_prefix(void) -+{ -+ return key_fingerprint_selection() == SSH_FP_SHA1 ? "sha1:" : ""; -+} -+ - /* - * Reads a multiple-precision integer in decimal from the buffer, and advances - * the pointer. The integer must already be initialized. This function is -diff --git a/key.h b/key.h -index d8ad13d..0e3eea5 100644 ---- a/key.h -+++ b/key.h -@@ -104,6 +104,9 @@ int key_equal_public(const Key *, const Key *); - int key_equal(const Key *, const Key *); - char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); - u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); -+enum fp_type key_fingerprint_selection(void); -+char *key_selected_fingerprint(Key *, enum fp_rep); -+char *key_fingerprint_prefix(void); - const char *key_type(const Key *); - const char *key_cert_type(const Key *); - int key_write(const Key *, FILE *); -diff --git a/ssh-add.c b/ssh-add.c -index 3421452..691949f 100644 ---- a/ssh-add.c -+++ b/ssh-add.c -@@ -330,10 +330,10 @@ list_identities(AuthenticationConnection *ac, int do_fp) - key = ssh_get_next_identity(ac, &comment, version)) { - had_identities = 1; - if (do_fp) { -- fp = key_fingerprint(key, SSH_FP_MD5, -- SSH_FP_HEX); -- printf("%d %s %s (%s)\n", -- key_size(key), fp, comment, key_type(key)); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ printf("%d %s%s %s (%s)\n", -+ key_size(key), key_fingerprint_prefix(), -+ fp, comment, key_type(key)); - free(fp); - } else { - if (!key_write(key, stdout)) -diff --git a/ssh-agent.c b/ssh-agent.c -index ba24612..117fdde 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -198,9 +198,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_selected_fingerprint(id->key, SSH_FP_HEX); -+ if (ask_permission("Allow use of key %s?\nKey fingerprint %s%s.", -+ id->comment, key_fingerprint_prefix(), p)) - ret = 0; - free(p); - -diff --git a/ssh-keygen.c b/ssh-keygen.c -index 2a316bc..482dc1c 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -783,13 +783,14 @@ do_fingerprint(struct passwd *pw) - { - FILE *f; - Key *public; -- char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; -+ char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra, *pfx; - int i, skip = 0, num = 0, invalid = 1; - enum fp_rep rep; - enum fp_type fptype; - struct stat st; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); -+ pfx = print_bubblebabble ? "" : key_fingerprint_prefix(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; - - if (!have_identity) -@@ -801,8 +802,8 @@ do_fingerprint(struct passwd *pw) - public = key_load_public(identity_file, &comment); - if (public != NULL) { - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, comment, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, comment, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -867,8 +868,8 @@ do_fingerprint(struct passwd *pw) - } - comment = *cp ? cp : comment; - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, - comment ? comment : "no comment", key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -986,13 +987,15 @@ printhost(FILE *f, const char *name, Key *public, int ca, int hash) - if (print_fingerprint) { - enum fp_rep rep; - enum fp_type fptype; -- char *fp, *ra; -+ char *fp, *ra, *pfx; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); -+ pfx = print_bubblebabble ? "" : key_fingerprint_prefix(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; -+ - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, name, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, name, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -1878,16 +1881,17 @@ do_show_cert(struct passwd *pw) - fatal("%s is not a certificate", identity_file); - v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; - -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- ca_fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX); - - printf("%s:\n", identity_file); - printf(" Type: %s %s certificate\n", key_ssh_name(key), - key_cert_type(key)); -- printf(" Public key: %s %s\n", key_type(key), key_fp); -- printf(" Signing CA: %s %s\n", -- key_type(key->cert->signature_key), ca_fp); -+ printf(" Public key: %s %s%s\n", key_type(key), -+ key_fingerprint_prefix(), key_fp); -+ printf(" Signing CA: %s %s%s\n", -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), ca_fp); - printf(" Key ID: \"%s\"\n", key->cert->key_id); - if (!v00) { - printf(" Serial: %llu\n", -@@ -2686,13 +2690,12 @@ 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, -- SSH_FP_RANDOMART); -+ char *fp = key_selected_fingerprint(public, SSH_FP_HEX); -+ char *ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); - printf("Your public key has been saved in %s.\n", - identity_file); - printf("The key fingerprint is:\n"); -- printf("%s %s\n", fp, comment); -+ printf("%s%s %s\n", key_fingerprint_prefix(), fp, comment); - printf("The key's randomart image is:\n"); - printf("%s\n", ra); - free(ra); -diff --git a/sshconnect.c b/sshconnect.c -index 573d7a8..394cca8 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -914,10 +914,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - "key for IP address '%.128s' to the list " - "of known hosts.", type, ip); - } else if (options.visual_host_key) { -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(host_key, SSH_FP_MD5, -- SSH_FP_RANDOMART); -- logit("Host key fingerprint is %s\n%s\n", fp, ra); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART); -+ logit("Host key fingerprint is %s%s\n%s\n", -+ key_fingerprint_prefix(), fp, ra); - free(ra); - free(fp); - } -@@ -955,9 +955,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - 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, -- SSH_FP_RANDOMART); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART); - msg2[0] = '\0'; - if (options.verify_host_key_dns) { - if (matching_host_key_dns) -@@ -972,10 +971,11 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - 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 fingerprint is %s%s.%s%s\n%s" - "Are you sure you want to continue connecting " - "(yes/no)? ", -- host, ip, msg1, type, fp, -+ host, ip, msg1, type, -+ key_fingerprint_prefix(), fp, - options.visual_host_key ? "\n" : "", - options.visual_host_key ? ra : "", - msg2); -@@ -1220,8 +1220,9 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) - int flags = 0; - char *fp; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- debug("Server host key: %s %s", key_type(host_key), fp); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ debug("Server host key: %s %s%s", key_type(host_key), -+ key_fingerprint_prefix(), fp); - free(fp); - - /* XXX certs are not yet supported for DNS */ -@@ -1327,14 +1328,15 @@ show_other_keys(struct hostkeys *hostkeys, Key *key) - continue; - if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) - continue; -- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); -+ fp = key_selected_fingerprint(found->key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(found->key, SSH_FP_RANDOMART); - logit("WARNING: %s key found for host %s\n" - "in %s:%lu\n" -- "%s key fingerprint %s.", -+ "%s key fingerprint %s%s.", - key_type(found->key), - found->host, found->file, found->line, -- key_type(found->key), fp); -+ key_type(found->key), -+ key_fingerprint_prefix(), fp); - if (options.visual_host_key) - logit("%s", ra); - free(ra); -@@ -1349,7 +1351,7 @@ warn_changed_key(Key *host_key) - { - char *fp; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); - - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); -@@ -1357,8 +1359,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 a host key has just been changed."); -- error("The fingerprint for the %s key sent by the remote host is\n%s.", -- key_type(host_key), fp); -+ error("The fingerprint for the %s key sent by the remote host is\n%s%s.", -+ key_type(host_key),key_fingerprint_prefix(), fp); - error("Please contact your system administrator."); - - free(fp); -diff --git a/sshconnect2.c b/sshconnect2.c -index 7f4ff41..adbbfc7 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -577,8 +577,9 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) - 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_selected_fingerprint(key, SSH_FP_HEX); -+ debug2("input_userauth_pk_ok: fp %s%s", -+ key_fingerprint_prefix(), fp); - free(fp); - - /* -@@ -986,8 +987,9 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) - int have_sig = 1; - char *fp; - -- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); -- debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); -+ fp = key_selected_fingerprint(id->key, SSH_FP_HEX); -+ debug3("sign_and_send_pubkey: %s %s%s", key_type(id->key), -+ key_fingerprint_prefix(), fp); - free(fp); - - if (key_to_blob(id->key, &blob, &bloblen) == 0) { diff --git a/openssh-6.6p1-fips.patch b/openssh-6.6p1-fips.patch deleted file mode 100644 index f97e2ba..0000000 --- a/openssh-6.6p1-fips.patch +++ /dev/null @@ -1,812 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 3bb7f00..294bef5 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -154,25 +154,25 @@ libssh.a: $(LIBSSH_OBJS) - $(RANLIB) $@ - - ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) -- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) -+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS) - - sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) -- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) -+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) - - 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) -@@ -187,7 +187,7 @@ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o - $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -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 --git a/auth-rsa.c b/auth-rsa.c -index f225b0b..8bafcd6 100644 ---- a/auth-rsa.c -+++ b/auth-rsa.c -@@ -244,7 +244,7 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file, - "actual %d vs. announced %d.", - file, linenum, BN_num_bits(key->rsa->n), bits); - -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); - debug("matching key found: file %s, line %lu %s %s", - file, linenum, key_type(key), fp); - free(fp); -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 6d1c872..3808ec8 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -214,8 +214,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) - } - - if (key_is_cert(key)) { -- fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX); - auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", - key_type(key), key->cert->key_id, - (unsigned long long)key->cert->serial, -@@ -223,7 +222,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) - extra == NULL ? "" : ", ", extra == NULL ? "" : extra); - free(fp); - } else { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); - auth_info(authctxt, "%s %s%s%s", key_type(key), fp, - extra == NULL ? "" : ", ", extra == NULL ? "" : extra); - free(fp); -diff --git a/authfile.c b/authfile.c -index ec4f4ff..2b3d650 100644 ---- a/authfile.c -+++ b/authfile.c -@@ -46,6 +46,7 @@ - #include - #include - #include -+#include - - /* compatibility with old or broken OpenSSL versions */ - #include "openbsd-compat/openssl-compat.h" -@@ -1068,7 +1069,7 @@ Key * - key_parse_private(Buffer *buffer, const char *filename, - const char *passphrase, char **commentp) - { -- Key *pub, *prv; -+ Key *pub, *prv = NULL; - - /* it's a SSH v1 key if the public key part is readable */ - pub = key_parse_public_rsa1(buffer, commentp); -@@ -1080,9 +1081,10 @@ key_parse_private(Buffer *buffer, const char *filename, - *commentp = xstrdup(filename); - } else { - key_free(pub); -- /* key_parse_public_rsa1() has already loaded the comment */ -- prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, -- NULL); -+ if (! FIPS_mode()) -+ /* key_parse_public_rsa1() has already loaded the comment */ -+ prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, -+ NULL); - } - return prv; - } -diff --git a/cipher-ctr.c b/cipher-ctr.c -index 73e9c7c..40ee395 100644 ---- a/cipher-ctr.c -+++ b/cipher-ctr.c -@@ -179,7 +179,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 --git a/cipher.c b/cipher.c -index 226e56d..b19443c 100644 ---- a/cipher.c -+++ b/cipher.c -@@ -39,6 +39,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -90,6 +92,25 @@ static const struct Cipher ciphers[] = { - { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } - }; - -+static const struct Cipher fips_ciphers[] = { -+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, -+ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, -+ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, -+ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, -+ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, -+ { "rijndael-cbc@lysator.liu.se", -+ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, -+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, -+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, -+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, -+#ifdef OPENSSL_HAVE_EVPGCM -+ { "aes128-gcm@openssh.com", -+ SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, -+ { "aes256-gcm@openssh.com", -+ SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, -+#endif -+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } -+}; - /*--*/ - - /* Returns a list of supported ciphers separated by the specified char. */ -@@ -100,7 +121,7 @@ cipher_alg_list(char sep, int auth_only) - size_t nlen, rlen = 0; - const Cipher *c; - -- for (c = ciphers; c->name != NULL; c++) { -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) { - if (c->number != SSH_CIPHER_SSH2) - continue; - if (auth_only && c->auth_len == 0) -@@ -180,7 +201,7 @@ const Cipher * - cipher_by_name(const char *name) - { - const 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; -@@ -190,7 +211,7 @@ const Cipher * - cipher_by_number(int id) - { - const 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; -@@ -232,7 +253,7 @@ cipher_number(const char *name) - const 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; -diff --git a/dh.h b/dh.h -index 48f7b68..9ff39f4 100644 ---- a/dh.h -+++ b/dh.h -@@ -45,6 +45,7 @@ int dh_estimate(int); - - /* Min and max values from RFC4419. */ - #define DH_GRP_MIN 1024 -+#define DH_GRP_MIN_FIPS 2048 - #define DH_GRP_MAX 8192 - - /* -diff --git a/entropy.c b/entropy.c -index b361a04..5616643 100644 ---- a/entropy.c -+++ b/entropy.c -@@ -222,6 +222,9 @@ seed_rng(void) - fatal("OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - -+ /* clean the PRNG status when exiting the program */ -+ atexit(RAND_cleanup); -+ - #ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - debug3("RNG is ready, skipping seeding"); -diff --git a/kex.c b/kex.c -index bc3e53e..ede7b67 100644 ---- a/kex.c -+++ b/kex.c -@@ -34,6 +34,7 @@ - #include - - #include -+#include - - #include "xmalloc.h" - #include "ssh2.h" -@@ -103,6 +104,25 @@ static const struct kexalg kexalgs[] = { - { NULL, -1, -1, -1}, - }; - -+static const struct kexalg kexalgs_fips[] = { -+ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+#ifdef HAVE_EVP_SHA256 -+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, -+#endif -+#ifdef OPENSSL_HAS_ECC -+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, -+ SSH_DIGEST_SHA384 }, -+# ifdef OPENSSL_HAS_NISTP521 -+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, -+ SSH_DIGEST_SHA512 }, -+# endif -+#endif -+ { NULL, -1, -1, NULL}, -+}; -+ - char * - kex_alg_list(char sep) - { -@@ -126,7 +146,7 @@ kex_alg_by_name(const char *name) - { - const struct kexalg *k; - -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) - return k; - #ifdef GSSAPI -@@ -151,7 +171,10 @@ kex_names_valid(const char *names) - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (kex_alg_by_name(p) == NULL) { -- error("Unsupported KEX algorithm \"%.100s\"", p); -+ if (FIPS_mode()) -+ error("\"%.100s\" is not allowed in FIPS mode", p); -+ else -+ error("Unsupported KEX algorithm \"%.100s\"", p); - free(s); - return 0; - } -diff --git a/kexecdhc.c b/kexecdhc.c -index 2f7629c..20c9946 100644 ---- a/kexecdhc.c -+++ b/kexecdhc.c -@@ -154,6 +154,7 @@ kexecdh_client(Kex *kex) - - kex_derive_keys_bn(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); -+ memset(hash, 0, hashlen); - kex_finish(kex); - } - #else /* OPENSSL_HAS_ECC */ -diff --git a/kexecdhs.c b/kexecdhs.c -index 2700b72..0820894 100644 ---- a/kexecdhs.c -+++ b/kexecdhs.c -@@ -150,6 +150,7 @@ kexecdh_server(Kex *kex) - - kex_derive_keys_bn(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); -+ memset(hash, 0, hashlen); - kex_finish(kex); - } - #else /* OPENSSL_HAS_ECC */ -diff --git a/kexgexc.c b/kexgexc.c -index 355b7ba..427e11f 100644 ---- a/kexgexc.c -+++ b/kexgexc.c -@@ -26,6 +26,8 @@ - - #include "includes.h" - -+#include -+ - #include - - #include -@@ -58,7 +60,7 @@ kexgex_client(Kex *kex) - int min, max, nbits; - DH *dh; - -- min = DH_GRP_MIN; -+ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - max = DH_GRP_MAX; - - /* Servers with MAX4096DH need a preferred size (nbits) <= 4096. -diff --git a/kexgexs.c b/kexgexs.c -index 770ad28..9d4fc6d 100644 ---- a/kexgexs.c -+++ b/kexgexs.c -@@ -76,16 +76,16 @@ kexgex_server(Kex *kex) - omin = min = packet_get_int(); - onbits = nbits = packet_get_int(); - omax = max = packet_get_int(); -- min = MAX(DH_GRP_MIN, min); -+ min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); - max = MIN(DH_GRP_MAX, max); -- nbits = MAX(DH_GRP_MIN, nbits); -+ nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); - nbits = MIN(DH_GRP_MAX, nbits); - break; - case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: - debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); - onbits = nbits = packet_get_int(); - /* unused for old GEX */ -- omin = min = DH_GRP_MIN; -+ omin = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - omax = max = DH_GRP_MAX; - break; - default: -diff --git a/key.c b/key.c -index 62f3edb..a2050f6 100644 ---- a/key.c -+++ b/key.c -@@ -42,6 +42,7 @@ - #include "crypto_api.h" - - #include -+#include - #include - - #include -@@ -636,9 +637,13 @@ key_fingerprint_selection(void) - char *env; - - if (!rv_defined) { -- env = getenv("SSH_FINGERPRINT_TYPE"); -- rv = (env && !strcmp (env, "sha")) ? -- SSH_FP_SHA1 : SSH_FP_MD5; -+ if (FIPS_mode()) -+ rv = SSH_FP_SHA1; -+ else { -+ env = getenv("SSH_FINGERPRINT_TYPE"); -+ rv = (env && !strcmp (env, "sha")) ? -+ SSH_FP_SHA1 : SSH_FP_MD5; -+ } - rv_defined = 1; - } - return rv; -@@ -1168,8 +1173,11 @@ rsa_generate_private_key(u_int bits) - fatal("%s: BN_new failed", __func__); - if (!BN_set_word(f4, RSA_F4)) - fatal("%s: BN_new failed", __func__); -- if (!RSA_generate_key_ex(private, bits, f4, NULL)) -+ if (!RSA_generate_key_ex(private, bits, f4, NULL)) { -+ if (FIPS_mode()) -+ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__); - fatal("%s: key generation failed.", __func__); -+ } - BN_free(f4); - return private; - } -diff --git a/mac.c b/mac.c -index 9388af4..cd7b034 100644 ---- a/mac.c -+++ b/mac.c -@@ -27,6 +27,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -60,7 +62,7 @@ struct macalg { - int etm; /* Encrypt-then-MAC */ - }; - --static const struct macalg macs[] = { -+static const struct macalg all_macs[] = { - /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ - { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, - { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, -@@ -91,6 +93,24 @@ static const struct macalg macs[] = { - { NULL, 0, 0, 0, 0, 0, 0 } - }; - -+static const struct macalg fips_macs[] = { -+ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ -+ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, -+#ifdef HAVE_EVP_SHA256 -+ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 }, -+ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, -+#endif -+ -+ /* Encrypt-then-MAC variants */ -+ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, -+#ifdef HAVE_EVP_SHA256 -+ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 }, -+ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 }, -+#endif -+ -+ { NULL, 0, 0, 0, 0, 0, 0 } -+}; -+ - /* Returns a list of supported MACs separated by the specified char. */ - char * - mac_alg_list(char sep) -@@ -99,7 +119,7 @@ mac_alg_list(char sep) - size_t nlen, rlen = 0; - const struct macalg *m; - -- for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(m->name); -@@ -133,7 +153,7 @@ mac_setup(Mac *mac, char *name) - { - const struct macalg *m; - -- for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { - if (strcmp(name, m->name) != 0) - continue; - if (mac != NULL) { -diff --git a/myproposal.h b/myproposal.h -index 3a0f5ae..4f35a44 100644 ---- a/myproposal.h -+++ b/myproposal.h -@@ -88,6 +88,12 @@ - "diffie-hellman-group14-sha1," \ - "diffie-hellman-group1-sha1" - -+#define KEX_DEFAULT_KEX_FIPS \ -+ KEX_ECDH_METHODS \ -+ KEX_SHA256_METHODS \ -+ "diffie-hellman-group-exchange-sha1," \ -+ "diffie-hellman-group14-sha1" -+ - #define KEX_DEFAULT_PK_ALG \ - HOSTKEY_ECDSA_CERT_METHODS \ - "ssh-ed25519-cert-v01@openssh.com," \ -@@ -133,6 +139,22 @@ - #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" -+#ifdef HAVE_EVP_SHA256 -+#define KEX_FIPS_MAC \ -+ "hmac-sha1," \ -+ "hmac-sha2-256," \ -+ "hmac-sha2-512," \ -+ "hmac-sha1-etm@openssh.com," \ -+ "hmac-sha2-256-etm@openssh.com," \ -+ "hmac-sha2-512-etm@openssh.com" -+#else -+#define KEX_FIPS_MAC \ -+ "hmac-sha1" -+#endif - - static char *myproposal[PROPOSAL_MAX] = { - KEX_DEFAULT_KEX, -diff --git a/ssh-keygen.c b/ssh-keygen.c -index 66198e6..ccf22c8 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -195,6 +195,12 @@ type_bits_valid(int type, u_int32_t *bitsp) - fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); - exit(1); - } -+ if (FIPS_mode()) { -+ if (type == KEY_DSA) -+ fatal("DSA keys are not allowed in FIPS mode"); -+ if (type == KEY_ED25519) -+ fatal("ED25519 keys are not allowed in FIPS mode"); -+ } - if (type == KEY_DSA && *bitsp != 1024) - fatal("DSA keys must be 1024 bits"); - else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768) -@@ -746,7 +752,7 @@ do_download(struct passwd *pw) - enum fp_type fptype; - char *fp, *ra; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; - - pkcs11_init(0); -@@ -756,8 +762,7 @@ do_download(struct passwd *pw) - for (i = 0; i < nkeys; i++) { - if (print_fingerprint) { - fp = key_fingerprint(keys[i], fptype, rep); -- ra = key_fingerprint(keys[i], SSH_FP_MD5, -- SSH_FP_RANDOMART); -+ ra = key_selected_fingerprint(keys[i], SSH_FP_RANDOMART); - printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), - fp, key_type(keys[i])); - if (log_level >= SYSLOG_LEVEL_VERBOSE) -diff --git a/ssh.c b/ssh.c -index 1e6cb90..ea9193f 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -73,6 +73,8 @@ - - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" - -@@ -427,6 +429,13 @@ main(int ac, char **av) - sanitise_stdfd(); - - __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)) -+ if (FIPS_mode()) -+ fatal("FIPS integrity verification test failed."); -+ else -+ logit("FIPS integrity verification test failed."); - - #ifndef HAVE_SETPROCTITLE - /* Prepare for later setproctitle emulation */ -@@ -504,6 +513,9 @@ main(int ac, char **av) - "ACD:E:F:I:KL:MNO:PQ:R: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': -@@ -828,7 +840,6 @@ main(int ac, char **av) - - host_arg = xstrdup(host); - -- OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - - /* Initialize the command to execute on remote host. */ -@@ -973,6 +984,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); - -@@ -1020,6 +1035,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, addrs, &hostaddr, options.port, - options.address_family, options.connection_attempts, -diff --git a/sshconnect2.c b/sshconnect2.c -index b00658b..6a1562c 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -44,6 +44,8 @@ - #include - #endif - -+#include -+ - #include "openbsd-compat/sys-queue.h" - - #include "xmalloc.h" -@@ -168,20 +170,25 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - - #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); -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ /* 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 -@@ -193,6 +200,10 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - 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]); -@@ -208,7 +219,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - 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] = - compat_pkalg_proposal(options.hostkeyalgorithms); -@@ -220,9 +235,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - } - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; -+ else if (FIPS_mode()) -+ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; -+ - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( - myproposal[PROPOSAL_KEX_ALGS]); -- - #ifdef GSSAPI - /* If we've got GSSAPI algorithms, then we also support the - * 'null' hostkey, as a last resort */ -diff --git a/sshd.c b/sshd.c -index b561ec8..e977de3 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -75,6 +75,8 @@ - #include - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - - #ifdef HAVE_SECUREWARE -@@ -1468,6 +1470,18 @@ main(int ac, char **av) - #endif - __progname = ssh_get_progname(av[0]); - -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)) { -+ openlog(__progname, LOG_PID, LOG_AUTHPRIV); -+ if (FIPS_mode()) { -+ syslog(LOG_CRIT, "FIPS integrity verification test failed."); -+ cleanup_exit(255); -+ } -+ else -+ syslog(LOG_INFO, "FIPS integrity verification test failed."); -+ closelog(); -+ } - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ - saved_argc = ac; - rexec_argc = ac; -@@ -1619,8 +1633,6 @@ main(int ac, char **av) - else - closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); - -- OpenSSL_add_all_algorithms(); -- - /* If requested, redirect the logs to the specified logfile. */ - if (logfile != NULL) { - log_redirect_stderr_to(logfile); -@@ -1798,6 +1810,10 @@ main(int ac, char **av) - debug("private host key: #%d type %d %s", i, keytype, - key_type(key ? key : pubkey)); - } -+ 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; -@@ -1961,6 +1977,10 @@ main(int ac, char **av) - /* Reinitialize the log (because of the fork above). */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - /* Chdir to the root directory so that the current disk can be - unmounted if desired. */ - if (chdir("/") == -1) -@@ -2530,6 +2550,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]); -@@ -2539,6 +2562,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] = -@@ -2549,6 +2575,8 @@ do_ssh2_kex(void) - } - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; -+ else if (FIPS_mode()) -+ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; - - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( - myproposal[PROPOSAL_KEX_ALGS]); -@@ -2575,10 +2603,14 @@ do_ssh2_kex(void) - if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) - orig = NULL; - -- if (options.gss_keyex) -- gss = ssh_gssapi_server_mechanisms(); -- else -- gss = NULL; -+ if (options.gss_keyex) { -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ gss = ssh_gssapi_server_mechanisms(); -+ } -+ } - - if (gss && orig) - xasprintf(&newstr, "%s,%s", gss, orig); diff --git a/openssh-6.6p1-force_krb.patch b/openssh-6.6p1-force_krb.patch index a242394..b7bc826 100644 --- a/openssh-6.6p1-force_krb.patch +++ b/openssh-6.6p1-force_krb.patch @@ -1,5 +1,5 @@ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 42de994..60de320 100644 +index 413b845..54dd383 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -32,7 +32,9 @@ @@ -12,12 +12,7 @@ index 42de994..60de320 100644 #include "xmalloc.h" #include "key.h" -@@ -40,10 +42,12 @@ - #include "auth.h" - #include "log.h" - #include "servconf.h" -+#include "misc.h" - +@@ -45,6 +47,7 @@ #include "buffer.h" #include "ssh-gss.h" @@ -25,7 +20,7 @@ index 42de994..60de320 100644 extern ServerOptions options; #ifdef HEIMDAL -@@ -55,6 +59,13 @@ extern ServerOptions options; +@@ -56,6 +59,13 @@ extern ServerOptions options; # include #endif @@ -39,7 +34,7 @@ index 42de994..60de320 100644 static krb5_context krb_context = NULL; /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ -@@ -87,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -88,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_principal princ; int retval; const char *errmsg; @@ -47,7 +42,7 @@ index 42de994..60de320 100644 if (ssh_gssapi_krb5_init() == 0) return 0; -@@ -98,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -99,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_free_error_message(krb_context, errmsg); return 0; } @@ -71,7 +66,7 @@ index 42de994..60de320 100644 } else retval = 0; -@@ -109,6 +133,135 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -110,6 +133,135 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) return retval; } @@ -208,10 +203,10 @@ index 42de994..60de320 100644 /* This writes out any forwarded credentials from the structure populated * during userauth. Called after we have setuid to the user */ diff --git a/session.c b/session.c -index b5dc144..ba4589b 100644 +index 28659ec..9c94d8e 100644 --- a/session.c +++ b/session.c -@@ -806,6 +806,29 @@ do_exec(Session *s, const char *command) +@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command) command = forced_command; forced = "(key-option)"; } @@ -257,10 +252,10 @@ index 0374c88..509109a 100644 /* draft-ietf-secsh-gsskeyex-06 */ diff --git a/sshd.8 b/sshd.8 -index 058d37a..5c4f15b 100644 +index adcaaf9..824163b 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -327,6 +327,7 @@ Finally, the server and the client enter an authentication dialog. +@@ -324,6 +324,7 @@ Finally, the server and the client enter an authentication dialog. The client tries to authenticate itself using host-based authentication, public key authentication, diff --git a/openssh-6.6p1-gsskex.patch b/openssh-6.6p1-gsskex.patch index 826acd4..6efa67d 100644 --- a/openssh-6.6p1-gsskex.patch +++ b/openssh-6.6p1-gsskex.patch @@ -1,8 +1,8 @@ diff --git a/Makefile.in b/Makefile.in -index 581b121..2ad26ff 100644 +index bbc3034..c9891e0 100644 --- a/Makefile.in +++ b/Makefile.in -@@ -77,6 +77,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ +@@ -87,6 +87,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ @@ -10,7 +10,7 @@ index 581b121..2ad26ff 100644 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o krl.o smult_curve25519_ref.o \ kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ -@@ -96,7 +97,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ +@@ -106,7 +107,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o \ monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ kexc25519s.o auth-krb5.o \ @@ -20,10 +20,10 @@ index 581b121..2ad26ff 100644 sftp-server.o sftp-common.o \ roaming_common.o roaming_serv.o \ diff --git a/auth2-gss.c b/auth2-gss.c -index 4756dd7..ad65059 100644 +index 4803e7e..222e3e0 100644 --- a/auth2-gss.c +++ b/auth2-gss.c -@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); +@@ -53,6 +53,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); static void input_gssapi_errtok(int, u_int32_t, void *); @@ -64,7 +64,7 @@ index 4756dd7..ad65059 100644 /* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -235,7 +269,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) +@@ -236,7 +270,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) packet_check_eom(); @@ -74,7 +74,7 @@ index 4756dd7..ad65059 100644 authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); -@@ -277,7 +312,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +@@ -278,7 +313,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) gssbuf.length = buffer_len(&b); if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) @@ -84,7 +84,7 @@ index 4756dd7..ad65059 100644 else logit("GSSAPI MIC check failed"); -@@ -294,6 +330,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +@@ -295,6 +331,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); } @@ -98,10 +98,10 @@ index 4756dd7..ad65059 100644 "gssapi-with-mic", userauth_gssapi, diff --git a/auth2.c b/auth2.c -index 5f4f26f..0f52b68 100644 +index d6fbc93..124d02b 100644 --- a/auth2.c +++ b/auth2.c -@@ -69,6 +69,7 @@ extern Authmethod method_passwd; +@@ -70,6 +70,7 @@ extern Authmethod method_passwd; extern Authmethod method_kbdint; extern Authmethod method_hostbased; #ifdef GSSAPI @@ -109,7 +109,7 @@ index 5f4f26f..0f52b68 100644 extern Authmethod method_gssapi; #endif -@@ -76,6 +77,7 @@ Authmethod *authmethods[] = { +@@ -77,6 +78,7 @@ Authmethod *authmethods[] = { &method_none, &method_pubkey, #ifdef GSSAPI @@ -118,7 +118,7 @@ index 5f4f26f..0f52b68 100644 #endif &method_passwd, diff --git a/clientloop.c b/clientloop.c -index 59ad3a2..9c60108 100644 +index 397c965..20ce0b5 100644 --- a/clientloop.c +++ b/clientloop.c @@ -111,6 +111,10 @@ @@ -132,7 +132,7 @@ index 59ad3a2..9c60108 100644 /* import options */ extern Options options; -@@ -1608,6 +1612,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) +@@ -1596,6 +1600,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); @@ -149,7 +149,7 @@ index 59ad3a2..9c60108 100644 debug("need rekeying"); xxx_kex->done = 0; diff --git a/configure.ac b/configure.ac -index 74e77db..9bde04e 100644 +index 8dedb95..2c4adac 100644 --- a/configure.ac +++ b/configure.ac @@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) @@ -526,10 +526,10 @@ index b39281b..a3a2289 100644 + #endif /* GSSAPI */ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 759fa10..42de994 100644 +index 795992d..413b845 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c -@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -121,7 +121,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) krb5_error_code problem; krb5_principal princ; OM_uint32 maj_status, min_status; @@ -538,7 +538,7 @@ index 759fa10..42de994 100644 const char *errmsg; if (client->creds == NULL) { -@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) return; } @@ -569,7 +569,7 @@ index 759fa10..42de994 100644 #ifdef USE_PAM if (options.use_pam) -@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -194,9 +209,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) krb5_cc_close(krb_context, ccache); @@ -646,7 +646,7 @@ index 759fa10..42de994 100644 ssh_gssapi_mech gssapi_kerberos_mech = { "toWM5Slw5Ew8Mqkay+al2g==", "Kerberos", -@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { +@@ -204,7 +286,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { NULL, &ssh_gssapi_krb5_userok, NULL, @@ -657,7 +657,7 @@ index 759fa10..42de994 100644 #endif /* KRB5 */ diff --git a/gss-serv.c b/gss-serv.c -index e61b37b..14f540e 100644 +index 5c59924..2289e8e 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -45,15 +45,20 @@ @@ -684,7 +684,7 @@ index e61b37b..14f540e 100644 #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; @@ -100,25 +105,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) - char lname[MAXHOSTNAMELEN]; + char lname[NI_MAXHOST]; gss_OID_set oidset; - gss_create_empty_oid_set(&status, &oidset); @@ -693,40 +693,40 @@ index e61b37b..14f540e 100644 + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); -- if (gethostname(lname, MAXHOSTNAMELEN)) { +- if (gethostname(lname, sizeof(lname))) { - gss_release_oid_set(&status, &oidset); - return (-1); - } -+ if (gethostname(lname, MAXHOSTNAMELEN)) { ++ if (gethostname(lname, sizeof(lname))) { + 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))) ++ 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); -- ++ } else { ++ ctx->name = GSS_C_NO_NAME; ++ ctx->creds = GSS_C_NO_CREDENTIAL; ++ return GSS_S_COMPLETE; ++ } + - gss_release_oid_set(&status, &oidset); - return (ctx->major); -+ return GSS_S_COMPLETE; } /* Privileged */ @@ -796,8 +796,7 @@ index e61b37b..14f540e 100644 + + 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); @@ -809,7 +808,8 @@ index e61b37b..14f540e 100644 + } + + debug("Marking rekeyed credentials for export"); -+ + +- gss_buffer_desc ename; + gss_release_name(&ctx->minor, &client->name); + gss_release_cred(&ctx->minor, &client->creds); + client->name = new_name; @@ -991,10 +991,10 @@ index e61b37b..14f540e 100644 #endif diff --git a/kex.c b/kex.c -index 74e2b86..bce2ab8 100644 +index a173e70..4563920 100644 --- a/kex.c +++ b/kex.c -@@ -51,6 +51,10 @@ +@@ -53,6 +53,10 @@ #include "roaming.h" #include "digest.h" @@ -1005,10 +1005,10 @@ index 74e2b86..bce2ab8 100644 #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) # define evp_ssh_sha256 EVP_sha256 -@@ -90,6 +94,11 @@ static const struct kexalg kexalgs[] = { +@@ -94,6 +98,11 @@ static const struct kexalg kexalgs[] = { #ifdef HAVE_EVP_SHA256 { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - #endif + #endif /* HAVE_EVP_SHA256 */ +#ifdef GSSAPI + { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, + { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, @@ -1017,7 +1017,7 @@ index 74e2b86..bce2ab8 100644 { NULL, -1, -1, -1}, }; -@@ -119,6 +128,12 @@ kex_alg_by_name(const char *name) +@@ -123,6 +132,12 @@ kex_alg_by_name(const char *name) for (k = kexalgs; k->name != NULL; k++) { if (strcmp(k->name, name) == 0) return k; @@ -1031,7 +1031,7 @@ index 74e2b86..bce2ab8 100644 return NULL; } diff --git a/kex.h b/kex.h -index c85680e..313bb51 100644 +index 4c40ec8..1c76c08 100644 --- a/kex.h +++ b/kex.h @@ -76,6 +76,11 @@ enum kex_exchange { @@ -1412,10 +1412,10 @@ index 0000000..e90b567 +#endif /* GSSAPI */ diff --git a/kexgsss.c b/kexgsss.c new file mode 100644 -index 0000000..6d7518c +index 0000000..b880998 --- /dev/null +++ b/kexgsss.c -@@ -0,0 +1,288 @@ +@@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1460,6 +1460,7 @@ index 0000000..6d7518c +#include "dh.h" +#include "ssh-gss.h" +#include "monitor_wrap.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ +#include "servconf.h" + +extern ServerOptions options; @@ -1704,35 +1705,11 @@ index 0000000..6d7518c + ssh_gssapi_rekey_creds(); +} +#endif /* GSSAPI */ -diff --git a/key.c b/key.c -index eb98ea8..900b9e3 100644 ---- a/key.c -+++ b/key.c -@@ -1013,6 +1013,7 @@ static const struct keytype keytypes[] = { - KEY_DSA_CERT_V00, 0, 1 }, - { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", - KEY_ED25519_CERT, 0, 1 }, -+ { "null", "null", KEY_NULL, 0, 0 }, - { NULL, NULL, -1, -1, 0 } - }; - -diff --git a/key.h b/key.h -index 0e3eea5..d51ed81 100644 ---- a/key.h -+++ b/key.h -@@ -46,6 +46,7 @@ enum types { - KEY_ED25519_CERT, - KEY_RSA_CERT_V00, - KEY_DSA_CERT_V00, -+ KEY_NULL, - KEY_UNSPEC - }; - enum fp_type { diff --git a/monitor.c b/monitor.c -index 229fada..aa70945 100644 +index d3f87e1..7ebc76e 100644 --- a/monitor.c +++ b/monitor.c -@@ -178,6 +178,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *); +@@ -181,6 +181,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 *); @@ -1741,7 +1718,7 @@ index 229fada..aa70945 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -253,11 +255,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -261,11 +263,18 @@ 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}, @@ -1757,10 +1734,10 @@ index 229fada..aa70945 100644 + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, +#endif + #ifdef WITH_OPENSSL {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, - {MONITOR_REQ_SIGN, 0, mm_answer_sign}, - {MONITOR_REQ_PTY, 0, mm_answer_pty}, -@@ -366,6 +375,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) + #endif +@@ -380,6 +389,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); @@ -1771,7 +1748,7 @@ index 229fada..aa70945 100644 } else { mon_dispatch = mon_dispatch_proto15; -@@ -471,6 +484,10 @@ monitor_child_postauth(struct monitor *pmonitor) +@@ -488,6 +501,10 @@ monitor_child_postauth(struct monitor *pmonitor) monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -1782,9 +1759,9 @@ index 229fada..aa70945 100644 } else { mon_dispatch = mon_dispatch_postauth15; monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -@@ -1866,6 +1883,13 @@ mm_get_kex(Buffer *m) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; +@@ -1893,6 +1910,13 @@ mm_get_kex(Buffer *m) kex->kex[KEX_ECDH_SHA2] = kexecdh_server; + #endif kex->kex[KEX_C25519_SHA256] = kexc25519_server; +#ifdef GSSAPI + if (options.gss_keyex) { @@ -1796,7 +1773,7 @@ index 229fada..aa70945 100644 kex->server = 1; kex->hostkey_type = buffer_get_int(m); kex->kex_type = buffer_get_int(m); -@@ -2073,6 +2097,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) +@@ -2100,6 +2124,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) OM_uint32 major; u_int len; @@ -1806,7 +1783,7 @@ index 229fada..aa70945 100644 goid.elements = buffer_get_string(m, &len); goid.length = len; -@@ -2100,6 +2127,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) +@@ -2127,6 +2154,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) OM_uint32 flags = 0; /* GSI needs this */ u_int len; @@ -1816,7 +1793,7 @@ index 229fada..aa70945 100644 in.value = buffer_get_string(m, &len); in.length = len; major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); -@@ -2117,6 +2147,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) +@@ -2144,6 +2174,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); @@ -1824,7 +1801,7 @@ index 229fada..aa70945 100644 } return (0); } -@@ -2128,6 +2159,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m) +@@ -2155,6 +2186,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m) OM_uint32 ret; u_int len; @@ -1834,7 +1811,7 @@ index 229fada..aa70945 100644 gssbuf.value = buffer_get_string(m, &len); gssbuf.length = len; mic.value = buffer_get_string(m, &len); -@@ -2154,7 +2188,11 @@ mm_answer_gss_userok(int sock, Buffer *m) +@@ -2181,7 +2215,11 @@ mm_answer_gss_userok(int sock, Buffer *m) { int authenticated; @@ -1847,7 +1824,7 @@ index 229fada..aa70945 100644 buffer_clear(m); buffer_put_int(m, authenticated); -@@ -2167,5 +2205,73 @@ mm_answer_gss_userok(int sock, Buffer *m) +@@ -2194,5 +2232,73 @@ mm_answer_gss_userok(int sock, Buffer *m) /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -1935,10 +1912,10 @@ index 20e2b4a..ff79fbb 100644 MONITOR_REQ_PAM_START = 100, MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, diff --git a/monitor_wrap.c b/monitor_wrap.c -index d1b6d99..d1e1caa 100644 +index 82f114c..7e991e6 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c -@@ -1290,7 +1290,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +@@ -1300,7 +1300,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) } int @@ -1947,7 +1924,7 @@ index d1b6d99..d1e1caa 100644 { Buffer m; int authenticated = 0; -@@ -1307,5 +1307,50 @@ mm_ssh_gssapi_userok(char *user) +@@ -1317,5 +1317,50 @@ mm_ssh_gssapi_userok(char *user) debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); return (authenticated); } @@ -2015,10 +1992,10 @@ index 9d5e5ba..93929e0 100644 #ifdef USE_PAM diff --git a/readconf.c b/readconf.c -index dc884c9..7613ff2 100644 +index 3f5c58b..1c07766 100644 --- a/readconf.c +++ b/readconf.c -@@ -141,6 +141,8 @@ typedef enum { +@@ -143,6 +143,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -2027,7 +2004,7 @@ index dc884c9..7613ff2 100644 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -183,10 +185,19 @@ static struct { +@@ -187,10 +189,19 @@ static struct { { "afstokenpassing", oUnsupported }, #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, @@ -2047,7 +2024,7 @@ index dc884c9..7613ff2 100644 #endif { "fallbacktorsh", oDeprecated }, { "usersh", oDeprecated }, -@@ -841,10 +852,30 @@ parse_time: +@@ -868,10 +879,30 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -2078,7 +2055,7 @@ index dc884c9..7613ff2 100644 case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -1497,7 +1528,12 @@ initialize_options(Options * options) +@@ -1553,7 +1584,12 @@ initialize_options(Options * options) options->pubkey_authentication = -1; options->challenge_response_authentication = -1; options->gss_authentication = -1; @@ -2091,7 +2068,7 @@ index dc884c9..7613ff2 100644 options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -1616,8 +1652,14 @@ fill_default_options(Options * options) +@@ -1677,8 +1713,14 @@ fill_default_options(Options * options) options->challenge_response_authentication = 1; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -2107,10 +2084,10 @@ index dc884c9..7613ff2 100644 options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) diff --git a/readconf.h b/readconf.h -index 75e3f8f..5cc97f0 100644 +index a028306..1dbe509 100644 --- a/readconf.h +++ b/readconf.h -@@ -54,7 +54,12 @@ typedef struct { +@@ -45,7 +45,12 @@ typedef struct { int challenge_response_authentication; /* Try S/Key or TIS, authentication. */ int gss_authentication; /* Try GSS authentication */ @@ -2150,10 +2127,10 @@ index b093a91..4c8da00 100644 type_has_legacy() { case $1 in diff --git a/regress/kextype.sh b/regress/kextype.sh -index 8c2ac09..a2a87ca 100644 +index 6f952f4..bcb609b 100644 --- a/regress/kextype.sh +++ b/regress/kextype.sh -@@ -9,6 +9,9 @@ cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak +@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/sshd_proxy tries="1 2 3 4" for k in `${SSH} -Q kex`; do @@ -2164,10 +2141,10 @@ index 8c2ac09..a2a87ca 100644 for i in $tries; do ${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true diff --git a/regress/rekey.sh b/regress/rekey.sh -index cf9401e..31fb0f7 100644 +index fd452b0..1148197 100644 --- a/regress/rekey.sh +++ b/regress/rekey.sh -@@ -30,6 +30,9 @@ increase_datafile_size 300 +@@ -38,6 +38,9 @@ increase_datafile_size 300 opts="" for i in `${SSH} -Q kex`; do @@ -2177,7 +2154,7 @@ index cf9401e..31fb0f7 100644 opts="$opts KexAlgorithms=$i" done for i in `${SSH} -Q cipher`; do -@@ -48,6 +51,9 @@ done +@@ -56,6 +59,9 @@ done if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then for c in `${SSH} -Q cipher-auth`; do for kex in `${SSH} -Q kex`; do @@ -2185,13 +2162,13 @@ index cf9401e..31fb0f7 100644 + continue + fi verbose "client rekey $c $kex" - ssh_data_rekeying -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex + ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c done diff --git a/servconf.c b/servconf.c -index f763317..68fb9ef 100644 +index c8a3f28..179c20d 100644 --- a/servconf.c +++ b/servconf.c -@@ -108,7 +108,10 @@ initialize_server_options(ServerOptions *options) +@@ -110,7 +110,10 @@ initialize_server_options(ServerOptions *options) options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -2202,7 +2179,7 @@ index f763317..68fb9ef 100644 options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->challenge_response_authentication = -1; -@@ -245,8 +248,14 @@ fill_default_server_options(ServerOptions *options) +@@ -253,8 +256,14 @@ fill_default_server_options(ServerOptions *options) options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -2217,7 +2194,7 @@ index f763317..68fb9ef 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -344,7 +353,8 @@ typedef enum { +@@ -359,7 +368,8 @@ typedef enum { sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, @@ -2227,7 +2204,7 @@ index f763317..68fb9ef 100644 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sHostCertificate, -@@ -411,10 +421,20 @@ static struct { +@@ -428,10 +438,20 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -2248,7 +2225,7 @@ index f763317..68fb9ef 100644 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, -@@ -1091,10 +1111,22 @@ process_server_config_line(ServerOptions *options, char *line, +@@ -1113,10 +1133,22 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->gss_authentication; goto parse_flag; @@ -2271,7 +2248,7 @@ index f763317..68fb9ef 100644 case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2005,6 +2037,9 @@ dump_config(ServerOptions *o) +@@ -2070,6 +2102,9 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); @@ -2282,10 +2259,10 @@ index f763317..68fb9ef 100644 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, diff --git a/servconf.h b/servconf.h -index 4572066..37cfa9b 100644 +index 21719e2..397698b 100644 --- a/servconf.h +++ b/servconf.h -@@ -112,7 +112,10 @@ typedef struct { +@@ -113,7 +113,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 */ @@ -2398,7 +2375,7 @@ index a99d7f0..0374c88 100644 #endif /* _SSH_GSS_H */ diff --git a/ssh_config b/ssh_config -index 6d1abaf..b0d343b 100644 +index 3f83c40..4a0fb82 100644 --- a/ssh_config +++ b/ssh_config @@ -26,6 +26,8 @@ @@ -2411,10 +2388,10 @@ index 6d1abaf..b0d343b 100644 # CheckHostIP yes # AddressFamily any diff --git a/ssh_config.5 b/ssh_config.5 -index b580392..e7accd6 100644 +index f9ede7a..e6649ac 100644 --- a/ssh_config.5 +++ b/ssh_config.5 -@@ -682,11 +682,43 @@ Specifies whether user authentication based on GSSAPI is allowed. +@@ -701,11 +701,43 @@ Specifies whether user authentication based on GSSAPI is allowed. The default is .Dq no . Note that this option applies to protocol version 2 only. @@ -2460,11 +2437,11 @@ index b580392..e7accd6 100644 Indicates that .Xr ssh 1 diff --git a/sshconnect2.c b/sshconnect2.c -index adbbfc7..cadf234 100644 +index 4724b66..703f8e4 100644 --- a/sshconnect2.c +++ b/sshconnect2.c -@@ -158,9 +158,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - { +@@ -159,9 +159,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; Kex *kex; +#ifdef GSSAPI @@ -2498,9 +2475,9 @@ index adbbfc7..cadf234 100644 if (options.ciphers == (char *)-1) { logit("No valid ciphers for protocol version 2 given, using defaults."); options.ciphers = NULL; -@@ -196,6 +221,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; +@@ -199,6 +224,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( + myproposal[PROPOSAL_KEX_ALGS]); +#ifdef GSSAPI + /* If we've got GSSAPI algorithms, then we also support the @@ -2516,9 +2493,9 @@ index adbbfc7..cadf234 100644 if (options.rekey_limit || options.rekey_interval) packet_set_rekey_limits((u_int32_t)options.rekey_limit, (time_t)options.rekey_interval); -@@ -208,10 +244,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; +@@ -213,10 +249,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) kex->kex[KEX_ECDH_SHA2] = kexecdh_client; + #endif kex->kex[KEX_C25519_SHA256] = kexc25519_client; +#ifdef GSSAPI + if (options.gss_keyex) { @@ -2547,7 +2524,7 @@ index adbbfc7..cadf234 100644 xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); -@@ -301,6 +357,7 @@ void input_gssapi_token(int type, u_int32_t, void *); +@@ -306,6 +362,7 @@ void input_gssapi_token(int type, u_int32_t, void *); 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 *); @@ -2555,7 +2532,7 @@ index adbbfc7..cadf234 100644 #endif void userauth(Authctxt *, char *); -@@ -316,6 +373,11 @@ static char *authmethods_get(void); +@@ -321,6 +378,11 @@ static char *authmethods_get(void); Authmethod authmethods[] = { #ifdef GSSAPI @@ -2567,7 +2544,7 @@ index adbbfc7..cadf234 100644 {"gssapi-with-mic", userauth_gssapi, NULL, -@@ -613,19 +675,31 @@ userauth_gssapi(Authctxt *authctxt) +@@ -617,19 +679,31 @@ userauth_gssapi(Authctxt *authctxt) static u_int mech = 0; OM_uint32 min; int ok = 0; @@ -2601,7 +2578,7 @@ index adbbfc7..cadf234 100644 ok = 1; /* Mechanism works */ } else { mech++; -@@ -722,8 +796,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) +@@ -726,8 +800,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) { Authctxt *authctxt = ctxt; Gssctxt *gssctxt; @@ -2612,7 +2589,7 @@ index adbbfc7..cadf234 100644 if (authctxt == NULL) fatal("input_gssapi_response: no authentication context"); -@@ -832,6 +906,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) +@@ -836,6 +910,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) free(msg); free(lang); } @@ -2662,21 +2639,10 @@ index adbbfc7..cadf234 100644 int diff --git a/sshd.c b/sshd.c -index 24ab272..e4e406e 100644 +index f7b8aba..2871fe9 100644 --- a/sshd.c +++ b/sshd.c -@@ -122,6 +122,10 @@ - #include "ssh-sandbox.h" - #include "version.h" - -+#ifdef USE_SECURITY_SESSION_API -+#include -+#endif -+ - #ifdef LIBWRAP - #include - #include -@@ -1744,10 +1748,13 @@ main(int ac, char **av) +@@ -1761,10 +1761,13 @@ main(int ac, char **av) logit("Disabling protocol version 1. Could not load host key"); options.protocol &= ~SSH_PROTO_1; } @@ -2690,7 +2656,7 @@ index 24ab272..e4e406e 100644 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { logit("sshd: no hostkeys available -- exiting."); exit(1); -@@ -2488,6 +2495,48 @@ do_ssh2_kex(void) +@@ -2501,6 +2504,49 @@ do_ssh2_kex(void) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( list_hostkey_types()); @@ -2736,12 +2702,13 @@ index 24ab272..e4e406e 100644 + } +#endif + ++ /* start key exchange */ kex = kex_setup(myproposal); - kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; -@@ -2496,6 +2545,13 @@ do_ssh2_kex(void) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; + #ifdef WITH_OPENSSL +@@ -2511,6 +2557,13 @@ do_ssh2_kex(void) kex->kex[KEX_ECDH_SHA2] = kexecdh_server; + #endif kex->kex[KEX_C25519_SHA256] = kexc25519_server; +#ifdef GSSAPI + if (options.gss_keyex) { @@ -2754,7 +2721,7 @@ index 24ab272..e4e406e 100644 kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; diff --git a/sshd_config b/sshd_config -index c1b7c03..adfd7b1 100644 +index 7061f75..f4796fc 100644 --- a/sshd_config +++ b/sshd_config @@ -91,6 +91,8 @@ ChallengeResponseAuthentication no @@ -2767,10 +2734,10 @@ index c1b7c03..adfd7b1 100644 # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will diff --git a/sshd_config.5 b/sshd_config.5 -index 95b5f8c..1fb002d 100644 +index cccb310..8ad79d9 100644 --- a/sshd_config.5 +++ b/sshd_config.5 -@@ -493,12 +493,40 @@ Specifies whether user authentication based on GSSAPI is allowed. +@@ -536,12 +536,40 @@ Specifies whether user authentication based on GSSAPI is allowed. The default is .Dq no . Note that this option applies to protocol version 2 only. diff --git a/openssh-6.6p1-keycat.patch b/openssh-6.6p1-keycat.patch index d30dedb..4cbe95d 100644 --- a/openssh-6.6p1-keycat.patch +++ b/openssh-6.6p1-keycat.patch @@ -17,7 +17,7 @@ index 0000000..630ec62 + + diff --git a/Makefile.in b/Makefile.in -index 411eadb..4ab6717 100644 +index f02aa1e..b225217 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server @@ -28,16 +28,16 @@ index 411eadb..4ab6717 100644 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -64,7 +65,7 @@ EXEEXT=@EXEEXT@ +@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ 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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -176,6 +177,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11 + LIBOPENSSH_OBJS=\ + ssherr.o \ +@@ -186,6 +187,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11 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) @@ -47,7 +47,7 @@ index 411eadb..4ab6717 100644 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) -@@ -283,6 +287,7 @@ install-files: +@@ -305,6 +309,7 @@ install-files: $(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ fi @@ -56,10 +56,10 @@ index 411eadb..4ab6717 100644 $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index c0ae0d4..cb0f931 100644 +index 12f5afd..269e642 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c -@@ -600,6 +600,14 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) +@@ -602,6 +602,14 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) _exit(1); } @@ -75,10 +75,10 @@ index c0ae0d4..cb0f931 100644 options.authorized_keys_command, user_pw->pw_name, NULL); diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index d04f4ed..0077dd7 100644 +index 265bd3a..8f32464 100644 --- a/openbsd-compat/port-linux-sshd.c +++ b/openbsd-compat/port-linux-sshd.c -@@ -53,6 +53,20 @@ extern Authctxt *the_authctxt; +@@ -54,6 +54,20 @@ extern Authctxt *the_authctxt; extern int inetd_flag; extern int rexeced_flag; @@ -99,7 +99,7 @@ index d04f4ed..0077dd7 100644 /* Send audit message */ static int sshd_selinux_send_audit_message(int success, security_context_t default_context, -@@ -307,7 +321,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -308,7 +322,7 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int @@ -108,7 +108,7 @@ index d04f4ed..0077dd7 100644 { const char *reqlvl; char *role; -@@ -318,16 +332,16 @@ sshd_selinux_setup_pam_variables(void) +@@ -319,16 +333,16 @@ sshd_selinux_setup_pam_variables(void) ssh_selinux_get_role_level(&role, &reqlvl); @@ -128,7 +128,7 @@ index d04f4ed..0077dd7 100644 if (role != NULL) free(role); -@@ -335,6 +349,24 @@ sshd_selinux_setup_pam_variables(void) +@@ -336,6 +350,24 @@ sshd_selinux_setup_pam_variables(void) return rv; } @@ -153,7 +153,7 @@ index d04f4ed..0077dd7 100644 /* Set the execution context to the default for the specified user */ void sshd_selinux_setup_exec_context(char *pwname) -@@ -343,7 +375,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -344,7 +376,7 @@ sshd_selinux_setup_exec_context(char *pwname) int r = 0; security_context_t default_ctx = NULL; @@ -162,7 +162,7 @@ index d04f4ed..0077dd7 100644 return; if (options.use_pam) { -@@ -414,7 +446,7 @@ sshd_selinux_copy_context(void) +@@ -415,7 +447,7 @@ sshd_selinux_copy_context(void) { security_context_t *ctx; @@ -187,10 +187,10 @@ index b18893c..cb51f99 100644 #ifdef LINUX_OOM_ADJUST diff --git a/platform.c b/platform.c -index 0d39ab2..0dae387 100644 +index 84c47fa..6d876cb 100644 --- a/platform.c +++ b/platform.c -@@ -102,7 +102,7 @@ platform_setusercontext(struct passwd *pw) +@@ -103,7 +103,7 @@ platform_setusercontext(struct passwd *pw) { #ifdef WITH_SELINUX /* Cache selinux status for later use */ diff --git a/openssh-6.6p1-keyperm.patch b/openssh-6.6p1-keyperm.patch index fccb328..fbe33b0 100644 --- a/openssh-6.6p1-keyperm.patch +++ b/openssh-6.6p1-keyperm.patch @@ -1,15 +1,16 @@ -diff -up openssh-6.6p1/authfile.c.keyperm openssh-6.6p1/authfile.c ---- openssh-6.6p1/authfile.c.keyperm 2014-02-04 01:20:15.000000000 +0100 -+++ openssh-6.6p1/authfile.c 2014-05-05 15:20:43.075246776 +0200 -@@ -54,6 +54,7 @@ +diff --git a/authfile.c b/authfile.c +index e93d867..4fc5b3d 100644 +--- a/authfile.c ++++ b/authfile.c +@@ -32,6 +32,7 @@ #include #include +#include - #include #include + #include #include -@@ -979,6 +980,13 @@ key_perm_ok(int fd, const char *filename +@@ -207,6 +208,13 @@ sshkey_perm_ok(int fd, const char *filename) #ifdef HAVE_CYGWIN if (check_ntsec(filename)) #endif diff --git a/openssh-6.6p1-kuserok.patch b/openssh-6.6p1-kuserok.patch index f7c5a1c..b0b12a6 100644 --- a/openssh-6.6p1-kuserok.patch +++ b/openssh-6.6p1-kuserok.patch @@ -1,8 +1,8 @@ diff --git a/auth-krb5.c b/auth-krb5.c -index 6c62bdf..11c8562 100644 +index 0089b18..8480261 100644 --- a/auth-krb5.c +++ b/auth-krb5.c -@@ -54,6 +54,21 @@ +@@ -55,6 +55,21 @@ extern ServerOptions options; @@ -24,7 +24,7 @@ index 6c62bdf..11c8562 100644 static int krb5_init(void *context) { -@@ -157,8 +172,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -158,8 +173,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) if (problem) goto out; @@ -37,7 +37,7 @@ index 6c62bdf..11c8562 100644 goto out; } diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 60de320..0a4930e 100644 +index 54dd383..961c564 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, @@ -175,27 +175,27 @@ index 60de320..0a4930e 100644 if ((fp = fopen(file, "r")) == NULL) { int saved_errno = errno; diff --git a/servconf.c b/servconf.c -index 68fb9ef..904c869 100644 +index 179c20d..d17ed04 100644 --- a/servconf.c +++ b/servconf.c -@@ -157,6 +157,7 @@ initialize_server_options(ServerOptions *options) - options->ip_qos_interactive = -1; +@@ -163,6 +163,7 @@ initialize_server_options(ServerOptions *options) options->ip_qos_bulk = -1; options->version_addendum = NULL; + options->fingerprint_hash = -1; + options->use_kuserok = -1; } void -@@ -312,6 +313,8 @@ fill_default_server_options(ServerOptions *options) - options->version_addendum = xstrdup(""); - if (options->show_patchlevel == -1) - options->show_patchlevel = 0; +@@ -328,6 +329,8 @@ fill_default_server_options(ServerOptions *options) + options->fwd_opts.streamlocal_bind_unlink = 0; + if (options->fingerprint_hash == -1) + options->fingerprint_hash = SSH_FP_HASH_DEFAULT; + if (options->use_kuserok == -1) + options->use_kuserok = 1; - /* Turn privilege separation on by default */ if (use_privsep == -1) -@@ -338,7 +341,7 @@ typedef enum { + use_privsep = PRIVSEP_NOSANDBOX; +@@ -353,7 +356,7 @@ typedef enum { sPermitRootLogin, sLogFacility, sLogLevel, sRhostsRSAAuthentication, sRSAAuthentication, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, @@ -204,7 +204,7 @@ index 68fb9ef..904c869 100644 sKerberosTgtPassing, sChallengeResponseAuthentication, sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, -@@ -410,11 +413,13 @@ static struct { +@@ -427,11 +430,13 @@ static struct { #else { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif @@ -218,7 +218,7 @@ index 68fb9ef..904c869 100644 #endif { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1526,6 +1531,10 @@ process_server_config_line(ServerOptions *options, char *line, +@@ -1557,6 +1562,10 @@ process_server_config_line(ServerOptions *options, char *line, *activep = value; break; @@ -229,7 +229,7 @@ index 68fb9ef..904c869 100644 case sPermitOpen: arg = strdelim(&cp); if (!arg || *arg == '\0') -@@ -1811,6 +1820,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) +@@ -1872,6 +1881,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(max_authtries); M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); @@ -237,19 +237,19 @@ index 68fb9ef..904c869 100644 M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); -@@ -2062,6 +2072,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sUseDNS, o->use_dns); - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); +@@ -2130,6 +2140,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); + dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); /* string arguments */ dump_cfg_string(sPidFile, o->pid_file); diff --git a/servconf.h b/servconf.h -index 37cfa9b..5117dfa 100644 +index 397698b..cf2a505 100644 --- a/servconf.h +++ b/servconf.h -@@ -173,6 +173,7 @@ typedef struct { +@@ -175,6 +175,7 @@ typedef struct { int num_permitted_opens; @@ -258,7 +258,7 @@ index 37cfa9b..5117dfa 100644 char *revoked_keys_file; char *trusted_user_ca_keys; diff --git a/sshd_config b/sshd_config -index adfd7b1..e772ed5 100644 +index f4796fc..0d9454d 100644 --- a/sshd_config +++ b/sshd_config @@ -87,6 +87,7 @@ ChallengeResponseAuthentication no @@ -270,10 +270,10 @@ index adfd7b1..e772ed5 100644 # GSSAPI options GSSAPIAuthentication yes diff --git a/sshd_config.5 b/sshd_config.5 -index 1fb002d..e0e5fff 100644 +index 8ad79d9..eb4dd9e 100644 --- a/sshd_config.5 +++ b/sshd_config.5 -@@ -697,6 +697,10 @@ Specifies whether to automatically destroy the user's ticket cache +@@ -740,6 +740,10 @@ Specifies whether to automatically destroy the user's ticket cache file on logout. The default is .Dq yes . @@ -284,7 +284,7 @@ index 1fb002d..e0e5fff 100644 .It Cm KexAlgorithms Specifies the available KEX (Key Exchange) algorithms. Multiple algorithms must be comma-separated. -@@ -862,6 +866,7 @@ Available keywords are +@@ -961,6 +965,7 @@ Available keywords are .Cm HostbasedUsesNameFromPacketOnly , .Cm KbdInteractiveAuthentication , .Cm KerberosAuthentication , diff --git a/openssh-6.6p1-ldap.patch b/openssh-6.6p1-ldap.patch deleted file mode 100644 index ae3e7cd..0000000 --- a/openssh-6.6p1-ldap.patch +++ /dev/null @@ -1,2674 +0,0 @@ -diff --git a/HOWTO.ldap-keys b/HOWTO.ldap-keys -new file mode 100644 -index 0000000..dd5f5cc ---- /dev/null -+++ b/HOWTO.ldap-keys -@@ -0,0 +1,108 @@ -+ -+HOW TO START -+ -+1) configure LDAP server -+ * Use LDAP server documentation -+2) add appropriate LDAP schema -+ * For OpenLDAP or SunONE Use attached schema, otherwise you have to create it. -+ * LDAP user entry -+ User entry: -+ - attached to the 'ldapPublicKey' objectclass -+ - attached to the 'posixAccount' objectclass -+ - with a filled 'sshPublicKey' attribute -+3) insert users into LDAP -+ * Use LDAP Tree management tool as useful -+ * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema and the additionnal lpk.schema. -+ * Example: -+ dn: uid=captain,ou=commanders,dc=enterprise,dc=universe -+ objectclass: top -+ objectclass: person -+ objectclass: organizationalPerson -+ objectclass: posixAccount -+ objectclass: ldapPublicKey -+ description: Jonathan Archer -+ userPassword: Porthos -+ cn: onathan Archer -+ sn: onathan Archer -+ uid: captain -+ uidNumber: 1001 -+ gidNumber: 1001 -+ homeDirectory: /home/captain -+ sshPublicKey: ssh-rss AAAAB3.... =captain@universe -+ sshPublicKey: command="kill -9 1" ssh-rss AAAAM5... -+4) on the ssh side set in sshd_config -+ * Set up the backend -+ AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper -+ AuthorizedKeysCommandUser -+ * Do not forget to set -+ PubkeyAuthentication yes -+ * Swith off unnecessary auth methods -+5) confugure ldap.conf -+ * Default ldap.conf is placed in /etc/ssh -+ * The configuration style is the same as other ldap based aplications -+6) if necessary edit ssh-ldap-wrapper -+ * There is a possibility to change ldap.conf location -+ * There are some debug options -+ * Example -+ /usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt -+ -+HOW TO MIGRATE FROM LPK -+ -+1) goto HOW TO START 4) .... the ldap schema is the same -+ -+2) convert the group requests to the appropriate LDAP requests -+ -+HOW TO SOLVE PROBLEMS -+ -+1) use debug in sshd -+ * /usr/sbin/sshd -d -d -d -d -+2) use debug in ssh-ldap-helper -+ * ssh-ldap-helper -d -d -d -d -s -+3) use tcpdump ... other ldap client etc. -+ -+ADVANTAGES -+ -+1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only). -+ -+DISADVANTAGES -+ -+1) LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP -+ allows write to users dn, somebody could replace some user's public key by his own and impersonate some -+ of your users in all your server farm -- be VERY CAREFUL. -+2) With incomplete PKI the MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login -+ as the impersonated user. -+3) If LDAP server is down there may be no fallback on passwd auth. -+ -+MISC. -+ -+1) todo -+ * Possibility to reuse the ssh-ldap-helper. -+ * Tune the LDAP part to accept all possible LDAP configurations. -+ -+2) differences from original lpk -+ * No LDAP code in sshd. -+ * Support for various LDAP platforms and configurations. -+ * LDAP is configured in separate ldap.conf file. -+ -+3) 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 ) -+ -+4) contributors/ideas/greets -+ - Eric AUGE -+ - Andrea Barisani -+ - Falk Siemonsmeier. -+ - Jacob Rief. -+ - Michael Durchgraf. -+ - frederic peters. -+ - Finlay dobbie. -+ - Stefan Fisher. -+ - Robin H. Johnson. -+ - Adrian Bridgett. -+ -+5) Author -+ Jan F. Chadima -+ -diff --git a/Makefile.in b/Makefile.in -index 28a8ec4..411eadb 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh - ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass - SFTP_SERVER=$(libexecdir)/sftp-server - SSH_KEYSIGN=$(libexecdir)/ssh-keysign -+SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper -+SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper - SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ - SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -60,8 +62,9 @@ XAUTH_PATH=@XAUTH_PATH@ - LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ - EXEEXT=@EXEEXT@ - MANFMT=@MANFMT@ -+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) 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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) - - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -98,8 +101,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ - sandbox-seccomp-filter.o sandbox-capsicum.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-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-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-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap-helper.8.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-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ssh-ldap-helper.8 ssh-ldap.conf.5 - MANTYPE = @MANTYPE@ - - CONFIGFILES=sshd_config.out ssh_config.out moduli.out -@@ -170,6 +173,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readco - 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) - -@@ -273,6 +279,10 @@ install-files: - $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) - $(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) ; \ -+ $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ -+ 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 -@@ -289,6 +299,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 -@@ -318,6 +332,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 \ -@@ -381,6 +402,8 @@ uninstall: - -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) - -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) - -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) -+ -rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT) -+ -rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT) - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -@@ -392,6 +415,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 - - regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c -diff --git a/configure.ac b/configure.ac -index 7c6ce08..722a19e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1625,6 +1625,106 @@ if test "x$use_pie" != "xno"; then - fi - fi - -+# 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([ \ - Blowfish_initstate \ -diff --git a/ldap-helper.c b/ldap-helper.c -new file mode 100644 -index 0000000..e95a94a ---- /dev/null -+++ b/ldap-helper.c -@@ -0,0 +1,155 @@ -+/* $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 in 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 { -+ usage(); -+ 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) { return NULL; } -+void buffer_put_string(Buffer *b, const void *f, u_int l) {} -+ -diff --git a/ldap-helper.h b/ldap-helper.h -new file mode 100644 -index 0000000..14cb29a ---- /dev/null -+++ b/ldap-helper.h -@@ -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 --git a/ldap.conf b/ldap.conf -new file mode 100644 -index 0000000..42e38d3 ---- /dev/null -+++ b/ldap.conf -@@ -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 --git a/ldapbody.c b/ldapbody.c -new file mode 100644 -index 0000000..3029108 ---- /dev/null -+++ b/ldapbody.c -@@ -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=%s)(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); -+ free (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 -+ (void) 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(options.account_class) + strlen (user); -+ if (options.ssh_filter != NULL) -+ bufflen += strlen (options.ssh_filter); -+ buffer = xmalloc (bufflen); -+ snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, options.account_class, 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)); -+ free (buffer); -+ return; -+ } -+ -+ /* free */ -+ free (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 --git a/ldapbody.h b/ldapbody.h -new file mode 100644 -index 0000000..665dca2 ---- /dev/null -+++ b/ldapbody.h -@@ -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 --git a/ldapconf.c b/ldapconf.c -new file mode 100644 -index 0000000..525060a ---- /dev/null -+++ b/ldapconf.c -@@ -0,0 +1,722 @@ -+/* $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, -+ lAccountClass, 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 }, -+ { "AccountClass", lAccountClass }, -+ { 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; -+} -+ -+/* Characters considered whitespace in strsep calls. */ -+#define WHITESPACE " \t\r\n" -+ -+/* return next token in configuration line */ -+static char * -+ldap_strdelim(char **s) -+{ -+ char *old; -+ int wspace = 0; -+ -+ if (*s == NULL) -+ return NULL; -+ -+ old = *s; -+ -+ *s = strpbrk(*s, WHITESPACE); -+ if (*s == NULL) -+ return (old); -+ -+ *s[0] = '\0'; -+ -+ /* Skip any extra whitespace after first token */ -+ *s += strspn(*s + 1, WHITESPACE) + 1; -+ if (*s[0] == '=' && !wspace) -+ *s += strspn(*s + 1, WHITESPACE) + 1; -+ -+ return (old); -+} -+ -+/* -+ * 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 = ldap_strdelim(&s)) == NULL) -+ return 0; -+ /* Ignore leading whitespace. */ -+ if (*keyword == '\0') -+ keyword = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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) -+ *intptr = value; -+ break; -+ -+ case lSSLPath: -+ charptr = &options.sslpath; -+ goto parse_string; -+ -+ case lSSL: -+ intptr = &options.ssl; -+ arg = ldap_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 = ldap_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 = ldap_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) -+ *intptr = value; -+ 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 lAccountClass: -+ charptr = &options.account_class; -+ goto parse_string; -+ -+ 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 = ldap_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; -+ options.account_class = 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 = ""; -+ if (options.account_class == NULL) -+ options.account_class = "posixAccount"; -+} -+ -+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); -+ dump_cfg_string(lAccountClass, options.logdir); -+} -+ -diff --git a/ldapconf.h b/ldapconf.h -new file mode 100644 -index 0000000..2cb550c ---- /dev/null -+++ b/ldapconf.h -@@ -0,0 +1,72 @@ -+/* $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; -+ char *account_class; -+} 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 --git a/ldapincludes.h b/ldapincludes.h -new file mode 100644 -index 0000000..8539bdc ---- /dev/null -+++ b/ldapincludes.h -@@ -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 --git a/ldapmisc.c b/ldapmisc.c -new file mode 100644 -index 0000000..de23c0c ---- /dev/null -+++ b/ldapmisc.c -@@ -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 --git a/ldapmisc.h b/ldapmisc.h -new file mode 100644 -index 0000000..4c271df ---- /dev/null -+++ b/ldapmisc.h -@@ -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 --git a/openssh-lpk-openldap.schema b/openssh-lpk-openldap.schema -new file mode 100644 -index 0000000..c84f90f ---- /dev/null -+++ b/openssh-lpk-openldap.schema -@@ -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 --git a/openssh-lpk-sun.schema b/openssh-lpk-sun.schema -new file mode 100644 -index 0000000..3136673 ---- /dev/null -+++ b/openssh-lpk-sun.schema -@@ -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 --git a/ssh-ldap-helper.8 b/ssh-ldap-helper.8 -new file mode 100644 -index 0000000..5d2d7be ---- /dev/null -+++ b/ssh-ldap-helper.8 -@@ -0,0 +1,79 @@ -+.\" $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-wrapper . -+.Pp -+.Nm -+is not intended to be invoked by the user, but from -+.Xr sshd 8 via -+.Xr ssh-ldap-wrapper . -+.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. -+.El -+.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/ssh-ldap-wrapper b/ssh-ldap-wrapper -new file mode 100644 -index 0000000..cb500aa ---- /dev/null -+++ b/ssh-ldap-wrapper -@@ -0,0 +1,4 @@ -+#!/bin/sh -+ -+exec /usr/libexec/openssh/ssh-ldap-helper -s "$1" -+ -diff --git a/ssh-ldap.conf.5 b/ssh-ldap.conf.5 -new file mode 100644 -index 0000000..f7081b8 ---- /dev/null -+++ b/ssh-ldap.conf.5 -@@ -0,0 +1,379 @@ -+.\" $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). -+.Bl -tag -width Ds -+.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 -+.Dq start_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. -+.It Cm AccountClass -+Specifies the LDAP class used to find user accounts. -+The default is posixAccount. -+.El -+.Sh FILES -+.Bl -tag -width Ds -+.It Pa /etc/ssh/ldap.conf -+Ldap configuration file for -+.Xr ssh-ldap-helper 8 . -+.El -+.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 --git a/openssh-6.6p1-role-mls.patch b/openssh-6.6p1-role-mls.patch index 4740c99..02e81e6 100644 --- a/openssh-6.6p1-role-mls.patch +++ b/openssh-6.6p1-role-mls.patch @@ -25,7 +25,7 @@ index a1a2b52..b109a5a 100644 char ** fetch_pam_child_environment(void); void free_pam_environment(char **); diff --git a/auth.h b/auth.h -index 124e597..4605588 100644 +index d081c94..847cffd 100644 --- a/auth.h +++ b/auth.h @@ -59,6 +59,9 @@ struct Authctxt { @@ -39,10 +39,10 @@ index 124e597..4605588 100644 char *info; /* Extra info for next auth_log */ #ifdef BSD_AUTH diff --git a/auth1.c b/auth1.c -index 0f870b3..df040bb 100644 +index 5038828..f0a98d2 100644 --- a/auth1.c +++ b/auth1.c -@@ -381,6 +381,9 @@ do_authentication(Authctxt *authctxt) +@@ -382,6 +382,9 @@ do_authentication(Authctxt *authctxt) { u_int ulen; char *user, *style = NULL; @@ -52,7 +52,7 @@ index 0f870b3..df040bb 100644 /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); -@@ -389,11 +392,24 @@ do_authentication(Authctxt *authctxt) +@@ -390,11 +393,24 @@ do_authentication(Authctxt *authctxt) user = packet_get_cstring(&ulen); packet_check_eom(); @@ -78,10 +78,10 @@ index 0f870b3..df040bb 100644 /* Verify that the user is a valid user. */ if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) diff --git a/auth2-gss.c b/auth2-gss.c -index c28a705..4756dd7 100644 +index 447f896..4803e7e 100644 --- a/auth2-gss.c +++ b/auth2-gss.c -@@ -251,6 +251,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +@@ -252,6 +252,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) Authctxt *authctxt = ctxt; Gssctxt *gssctxt; int authenticated = 0; @@ -89,7 +89,7 @@ index c28a705..4756dd7 100644 Buffer b; gss_buffer_desc mic, gssbuf; u_int len; -@@ -263,7 +264,13 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +@@ -264,7 +265,13 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) mic.value = packet_get_string(&len); mic.length = len; @@ -104,7 +104,7 @@ index c28a705..4756dd7 100644 "gssapi-with-mic"); gssbuf.value = buffer_ptr(&b); -@@ -275,6 +282,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +@@ -276,6 +283,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) logit("GSSAPI MIC check failed"); buffer_free(&b); @@ -114,10 +114,10 @@ index c28a705..4756dd7 100644 authctxt->postponed = 0; diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index eca0069..95d678e 100644 +index b7ae353..41f1a3f 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c -@@ -112,7 +112,15 @@ userauth_hostbased(Authctxt *authctxt) +@@ -113,7 +113,15 @@ userauth_hostbased(Authctxt *authctxt) buffer_put_string(&b, session_id2, session_id2_len); /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); @@ -135,7 +135,7 @@ index eca0069..95d678e 100644 buffer_put_cstring(&b, "hostbased"); buffer_put_string(&b, pkalg, alen); diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 749b11a..c0ae0d4 100644 +index 3f4f789..12f5afd 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -133,9 +133,11 @@ userauth_pubkey(Authctxt *authctxt) @@ -153,10 +153,10 @@ index 749b11a..c0ae0d4 100644 free(userstyle); buffer_put_cstring(&b, diff --git a/auth2.c b/auth2.c -index a5490c0..5f4f26f 100644 +index d9b440a..d6fbc93 100644 --- a/auth2.c +++ b/auth2.c -@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) +@@ -216,6 +216,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; @@ -166,7 +166,7 @@ index a5490c0..5f4f26f 100644 int authenticated = 0; if (authctxt == NULL) -@@ -226,6 +229,11 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) +@@ -227,6 +230,11 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); @@ -178,7 +178,7 @@ index a5490c0..5f4f26f 100644 if ((style = strchr(user, ':')) != NULL) *style++ = 0; -@@ -251,8 +259,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) +@@ -252,8 +260,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) use_privsep ? " [net]" : ""); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; @@ -196,10 +196,10 @@ index a5490c0..5f4f26f 100644 if (auth2_setup_methods_lists(authctxt) != 0) packet_disconnect("no authentication methods enabled"); diff --git a/misc.c b/misc.c -index e4c8c32..f31cd91 100644 +index 94b05b0..651c21b 100644 --- a/misc.c +++ b/misc.c -@@ -430,6 +430,7 @@ char * +@@ -431,6 +431,7 @@ char * colon(char *cp) { int flag = 0; @@ -207,7 +207,7 @@ index e4c8c32..f31cd91 100644 if (*cp == ':') /* Leading colon is part of file name. */ return NULL; -@@ -445,6 +446,13 @@ colon(char *cp) +@@ -446,6 +447,13 @@ colon(char *cp) return (cp); if (*cp == '/') return NULL; @@ -222,10 +222,10 @@ index e4c8c32..f31cd91 100644 return NULL; } diff --git a/monitor.c b/monitor.c -index 531c4f9..229fada 100644 +index dbe29f1..d3f87e1 100644 --- a/monitor.c +++ b/monitor.c -@@ -145,6 +145,9 @@ int mm_answer_sign(int, Buffer *); +@@ -148,6 +148,9 @@ int mm_answer_sign(int, Buffer *); int mm_answer_pwnamallow(int, Buffer *); int mm_answer_auth2_read_banner(int, Buffer *); int mm_answer_authserv(int, Buffer *); @@ -235,7 +235,7 @@ index 531c4f9..229fada 100644 int mm_answer_authpassword(int, Buffer *); int mm_answer_bsdauthquery(int, Buffer *); int mm_answer_bsdauthrespond(int, Buffer *); -@@ -219,6 +222,9 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -227,6 +230,9 @@ struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, @@ -245,7 +245,7 @@ index 531c4f9..229fada 100644 {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, #ifdef USE_PAM -@@ -805,6 +811,9 @@ mm_answer_pwnamallow(int sock, Buffer *m) +@@ -824,6 +830,9 @@ mm_answer_pwnamallow(int sock, Buffer *m) else { /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); @@ -255,7 +255,7 @@ index 531c4f9..229fada 100644 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); } #ifdef USE_PAM -@@ -846,6 +855,25 @@ mm_answer_authserv(int sock, Buffer *m) +@@ -865,6 +874,25 @@ mm_answer_authserv(int sock, Buffer *m) return (0); } @@ -281,7 +281,7 @@ index 531c4f9..229fada 100644 int mm_answer_authpassword(int sock, Buffer *m) { -@@ -1220,7 +1248,7 @@ static int +@@ -1241,7 +1269,7 @@ static int monitor_valid_userblob(u_char *data, u_int datalen) { Buffer b; @@ -290,7 +290,7 @@ index 531c4f9..229fada 100644 u_int len; int fail = 0; -@@ -1246,6 +1274,8 @@ monitor_valid_userblob(u_char *data, u_int datalen) +@@ -1267,6 +1295,8 @@ monitor_valid_userblob(u_char *data, u_int datalen) if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) fail++; p = buffer_get_cstring(&b, NULL); @@ -299,7 +299,7 @@ index 531c4f9..229fada 100644 xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); -@@ -1281,7 +1311,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, +@@ -1302,7 +1332,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, char *chost) { Buffer b; @@ -308,7 +308,7 @@ index 531c4f9..229fada 100644 u_int len; int fail = 0; -@@ -1298,6 +1328,8 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, +@@ -1319,6 +1349,8 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) fail++; p = buffer_get_cstring(&b, NULL); @@ -333,10 +333,10 @@ index 5bc41b5..20e2b4a 100644 MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105, diff --git a/monitor_wrap.c b/monitor_wrap.c -index 1a47e41..d1b6d99 100644 +index 45dc169..82f114c 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c -@@ -336,6 +336,25 @@ mm_inform_authserv(char *service, char *style) +@@ -342,6 +342,25 @@ mm_inform_authserv(char *service, char *style) buffer_free(&m); } @@ -377,12 +377,12 @@ index 18c2501..9d5e5ba 100644 char *mm_auth2_read_banner(void); int mm_auth_password(struct Authctxt *, char *); diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in -index 6ecfb93..b912dbe 100644 +index ab1a3e3..843225d 100644 --- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di - COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o + COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o -PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o +PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o @@ -391,10 +391,10 @@ index 6ecfb93..b912dbe 100644 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c new file mode 100644 -index 0000000..c18524e +index 0000000..6310717 --- /dev/null +++ b/openbsd-compat/port-linux-sshd.c -@@ -0,0 +1,414 @@ +@@ -0,0 +1,415 @@ +/* + * Copyright (c) 2005 Daniel Walsh + * Copyright (c) 2014 Petr Lautrbach @@ -426,6 +426,7 @@ index 0000000..c18524e + +#include "log.h" +#include "xmalloc.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ +#include "servconf.h" +#include "port-linux.h" +#include "key.h" @@ -868,10 +869,10 @@ index e3d1004..8ef6cc4 100644 #ifdef LINUX_OOM_ADJUST diff --git a/platform.c b/platform.c -index 30fc609..0d39ab2 100644 +index ee313da..84c47fa 100644 --- a/platform.c +++ b/platform.c -@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(struct passwd *pw) +@@ -184,7 +184,7 @@ platform_setusercontext_post_groups(struct passwd *pw) } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX @@ -881,10 +882,10 @@ index 30fc609..0d39ab2 100644 } diff --git a/sshd.c b/sshd.c -index 7523de9..07f9926 100644 +index 481d001..41b317b 100644 --- a/sshd.c +++ b/sshd.c -@@ -2138,6 +2138,9 @@ main(int ac, char **av) +@@ -2144,6 +2144,9 @@ main(int ac, char **av) restore_uid(); } #endif diff --git a/openssh-6.7p1-audit.patch b/openssh-6.7p1-audit.patch new file mode 100644 index 0000000..4ce4b53 --- /dev/null +++ b/openssh-6.7p1-audit.patch @@ -0,0 +1,2374 @@ +diff --git a/Makefile.in b/Makefile.in +index 8e11217..9311e16 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -92,7 +92,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + ssh-pkcs11.o krl.o smult_curve25519_ref.o \ + kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \ +- sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o ++ sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ ++ auditstub.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ +diff --git a/audit-bsm.c b/audit-bsm.c +index 6135591..c7a1b47 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -375,10 +375,23 @@ audit_connection_from(const char *host, int port) + #endif + } + +-void ++int + audit_run_command(const char *command) + { + /* not implemented */ ++ return 0; ++} ++ ++void ++audit_end_command(int handle, const char *command) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_count_session_open(void) ++{ ++ /* not necessary */ + } + + void +@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li) + /* not implemented */ + } + ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ /* not implemented */ ++} ++ + void + audit_event(ssh_audit_event_t event) + { +@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) + debug("%s: unhandled event %d", __func__, event); + } + } ++ ++void ++audit_unsupported_body(int what) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_generate_ephemeral_server_key(const char *fp) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff --git a/audit-linux.c b/audit-linux.c +index b3ee2f4..bff8180 100644 +--- a/audit-linux.c ++++ b/audit-linux.c +@@ -35,13 +35,25 @@ + + #include "log.h" + #include "audit.h" ++#include "key.h" ++#include "hostfile.h" ++#include "auth.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ ++#include "servconf.h" + #include "canohost.h" ++#include "packet.h" ++#include "cipher.h" + ++#define AUDIT_LOG_SIZE 256 ++ ++extern ServerOptions options; ++extern Authctxt *the_authctxt; ++extern u_int utmp_len; + const char* audit_username(void); + +-int +-linux_audit_record_event(int uid, const char *username, +- const char *hostname, const char *ip, const char *ttyn, int success) ++static void ++linux_audit_user_logxxx(int uid, const char *username, ++ const char *hostname, const char *ip, const char *ttyn, int success, int event) + { + int audit_fd, rc, saved_errno; + +@@ -49,11 +61,11 @@ linux_audit_record_event(int uid, const char *username, + if (audit_fd < 0) { + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) +- return 1; /* No audit support in kernel */ ++ return; /* No audit support in kernel */ + else +- return 0; /* Must prevent login */ ++ goto fatal_report; /* Must prevent login */ + } +- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, ++ rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", + username == NULL ? uid : -1, hostname, ip, ttyn, success); + saved_errno = errno; +@@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const char *username, + if ((rc == -EPERM) && (geteuid() != 0)) + rc = 0; + errno = saved_errno; +- return (rc >= 0); ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } + } + ++static void ++linux_audit_user_auth(int uid, const char *username, ++ const char *hostname, const char *ip, const char *ttyn, int success, int event) ++{ ++ int audit_fd, rc, saved_errno; ++ static const char *event_name[] = { ++ "maxtries exceeded", ++ "root denied", ++ "success", ++ "none", ++ "password", ++ "challenge-response", ++ "pubkey", ++ "hostbased", ++ "gssapi", ++ "invalid user", ++ "nologin", ++ "connection closed", ++ "connection abandoned", ++ "unknown" ++ }; ++ ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return; /* No audit support in kernel */ ++ else ++ goto fatal_report; /* Must prevent login */ ++ } ++ ++ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) ++ event = SSH_AUDIT_UNKNOWN; ++ ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, ++ NULL, event_name[event], username ? username : "(unknown)", ++ username == NULL ? uid : -1, hostname, ip, ttyn, success); ++ saved_errno = errno; ++ close(audit_fd); ++ /* ++ * Do not report error if the error is EPERM and sshd is run as non ++ * root user. ++ */ ++ if ((rc == -EPERM) && (geteuid() != 0)) ++ rc = 0; ++ errno = saved_errno; ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } ++} ++ ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, rc, saved_errno; ++ ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return 1; /* No audit support in kernel */ ++ else ++ return 0; /* Must prevent login */ ++ } ++ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ /* is the fingerprint_prefix() still needed? ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", ++ type, bits, key_fingerprint_prefix(), fp, get_remote_port()); ++ */ ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d", ++ type, bits, fp, get_remote_port()); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); ++out: ++ saved_errno = errno; ++ audit_close(audit_fd); ++ errno = saved_errno; ++ /* do not report error if the error is EPERM and sshd is run as non root user */ ++ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); ++} ++ ++static int user_login_count = 0; ++ + /* Below is the sshd audit API code */ + + void + audit_connection_from(const char *host, int port) + { +-} + /* not implemented */ ++} + +-void ++int + audit_run_command(const char *command) + { +- /* not implemented */ ++ if (!user_login_count++) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_START); ++ return 0; ++} ++ ++void ++audit_end_command(int handle, const char *command) ++{ ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGOUT); ++} ++ ++void ++audit_count_session_open(void) ++{ ++ user_login_count++; + } + + void + audit_session_open(struct logininfo *li) + { +- if (linux_audit_record_event(li->uid, NULL, li->hostname, +- NULL, li->line, 1) == 0) +- fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ if (!user_login_count++) ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_START); + } + + void + audit_session_close(struct logininfo *li) + { +- /* not implemented */ ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_LOGOUT); + } + + void +@@ -101,21 +232,43 @@ audit_event(ssh_audit_event_t event) + { + switch(event) { + case SSH_AUTH_SUCCESS: +- case SSH_CONNECTION_CLOSE: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ get_remote_ipaddr(), "ssh", 1, event); ++ break; ++ + case SSH_NOLOGIN: +- case SSH_LOGIN_EXCEED_MAXTRIES: + case SSH_LOGIN_ROOT_DENIED: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ get_remote_ipaddr(), "ssh", 0, event); ++ linux_audit_user_logxxx(-1, audit_username(), NULL, ++ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); + break; + ++ case SSH_LOGIN_EXCEED_MAXTRIES: + case SSH_AUTH_FAIL_NONE: + case SSH_AUTH_FAIL_PASSWD: + case SSH_AUTH_FAIL_KBDINT: + case SSH_AUTH_FAIL_PUBKEY: + case SSH_AUTH_FAIL_HOSTBASED: + case SSH_AUTH_FAIL_GSSAPI: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ get_remote_ipaddr(), "ssh", 0, event); ++ break; ++ ++ case SSH_CONNECTION_CLOSE: ++ if (user_login_count) { ++ while (user_login_count--) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_END); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGOUT); ++ } ++ break; ++ ++ case SSH_CONNECTION_ABANDON: + case SSH_INVALID_USER: +- linux_audit_record_event(-1, audit_username(), NULL, +- get_remote_ipaddr(), "sshd", 0); ++ linux_audit_user_logxxx(-1, audit_username(), NULL, ++ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); + break; + + default: +@@ -123,4 +276,135 @@ audit_event(ssh_audit_event_t event) + } + } + ++void ++audit_unsupported_body(int what) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ const static char *name[] = { "cipher", "mac", "comp" }; ++ char *s; ++ int audit_fd; ++ ++ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", ++ name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), ++ get_local_port()); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) ++ /* no problem, the next instruction will be fatal() */ ++ return; ++ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, get_remote_ipaddr(), NULL, 0); ++ audit_close(audit_fd); ++#endif ++} ++ ++const static char *direction[] = { "from-server", "from-client", "both" }; ++ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ const Cipher *cipher = cipher_by_name(enc); ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, ++ (intmax_t)pid, (intmax_t)uid, ++ get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return; /* No audit support in kernel */ ++ else ++ fatal("cannot open audit"); /* Must prevent login */ ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, get_remote_ipaddr(), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ fatal("cannot write into audit"); /* Must prevent login */ ++#endif ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], (intmax_t)pid, (intmax_t)uid, ++ get_remote_port(), ++ (s = get_local_ipaddr(packet_get_connection_in())), ++ get_local_port()); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, get_remote_ipaddr(), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", ++ fp, (intmax_t)pid, (intmax_t)uid); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, ++ listening_for_clients() ? NULL : get_remote_ipaddr(), ++ NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} ++ ++void ++audit_generate_ephemeral_server_key(const char *fp) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, 0, NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} + #endif /* USE_LINUX_AUDIT */ +diff --git a/audit.c b/audit.c +index ced57fa..18908b4 100644 +--- a/audit.c ++++ b/audit.c +@@ -28,6 +28,7 @@ + + #include + #include ++#include + + #ifdef SSH_AUDIT_EVENTS + +@@ -36,6 +37,11 @@ + #include "key.h" + #include "hostfile.h" + #include "auth.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "xmalloc.h" ++#include "misc.h" ++#include "servconf.h" + + /* + * Care must be taken when using this since it WILL NOT be initialized when +@@ -43,6 +49,7 @@ + * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. + */ + extern Authctxt *the_authctxt; ++extern ServerOptions options; + + /* Maybe add the audit class to struct Authmethod? */ + ssh_audit_event_t +@@ -71,13 +78,10 @@ audit_classify_auth(const char *method) + const char * + audit_username(void) + { +- static const char unknownuser[] = "(unknown user)"; +- static const char invaliduser[] = "(invalid user)"; ++ static const char unknownuser[] = "(unknown)"; + +- if (the_authctxt == NULL || the_authctxt->user == NULL) ++ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) + return (unknownuser); +- if (!the_authctxt->valid) +- return (invaliduser); + return (the_authctxt->user); + } + +@@ -111,6 +115,40 @@ audit_event_lookup(ssh_audit_event_t ev) + return(event_lookup[i].name); + } + ++void ++audit_key(int host_user, int *rv, const Key *key) ++{ ++ char *fp; ++ const char *crypto_name; ++ ++ fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (key->type == KEY_RSA1) ++ crypto_name = "ssh-rsa1"; ++ else ++ crypto_name = key_ssh_name(key); ++ if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) ++ *rv = 0; ++ free(fp); ++} ++ ++void ++audit_unsupported(int what) ++{ ++ PRIVSEP(audit_unsupported_body(what)); ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); ++} ++ ++void ++audit_session_key_free(int ctos) ++{ ++ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. +@@ -140,6 +178,17 @@ audit_event(ssh_audit_event_t event) + } + + /* ++ * Called when a child process has called, or will soon call, ++ * audit_session_open. ++ */ ++void ++audit_count_session_open(void) ++{ ++ debug("audit count session open euid %d user %s", geteuid(), ++ audit_username()); ++} ++ ++/* + * Called when a user session is started. Argument is the tty allocated to + * the session, or NULL if no tty was allocated. + * +@@ -174,13 +223,91 @@ audit_session_close(struct logininfo *li) + /* + * This will be called when a user runs a non-interactive command. Note that + * it may be called multiple times for a single connection since SSH2 allows +- * multiple sessions within a single connection. ++ * multiple sessions within a single connection. Returns a "handle" for ++ * audit_end_command. + */ +-void ++int + audit_run_command(const char *command) + { + debug("audit run command euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); ++ return 0; ++} ++ ++/* ++ * This will be called when the non-interactive command finishes. Note that ++ * it may be called multiple times for a single connection since SSH2 allows ++ * multiple sessions within a single connection. "handle" should come from ++ * the corresponding audit_run_command. ++ */ ++void ++audit_end_command(int handle, const char *command) ++{ ++ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), ++ audit_username(), command); ++} ++ ++/* ++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. ++ * ++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. ++ */ ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, ++ key_fingerprint_prefix(), fp, rv); ++} ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, ++ (unsigned)uid); ++} ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on destroy private part of the server key ++ */ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", ++ geteuid(), fp, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on generation of the ephemeral server key ++ */ ++void ++audit_generate_ephemeral_server_key(const char *) ++{ ++ debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); + } + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/audit.h b/audit.h +index 92ede5b..903df66 100644 +--- a/audit.h ++++ b/audit.h +@@ -28,6 +28,7 @@ + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "key.h" + + enum ssh_audit_event_type { + SSH_LOGIN_EXCEED_MAXTRIES, +@@ -47,11 +48,25 @@ enum ssh_audit_event_type { + }; + typedef enum ssh_audit_event_type ssh_audit_event_t; + ++int listening_for_clients(void); ++ + void audit_connection_from(const char *, int); + void audit_event(ssh_audit_event_t); ++void audit_count_session_open(void); + void audit_session_open(struct logininfo *); + void audit_session_close(struct logininfo *); +-void audit_run_command(const char *); ++int audit_run_command(const char *); ++void audit_end_command(int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); ++int audit_keyusage(int, const char *, unsigned, char *, int); ++void audit_key(int, int *, const Key *); ++void audit_unsupported(int); ++void audit_kex(int, char *, char *, char *, char *); ++void audit_unsupported_body(int); ++void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(int ctos); ++void audit_session_key_free_body(int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(const char *, pid_t, uid_t); ++void audit_generate_ephemeral_server_key(const char *); + + #endif /* _SSH_AUDIT_H */ +diff --git a/auditstub.c b/auditstub.c +new file mode 100644 +index 0000000..116f460 +--- /dev/null ++++ b/auditstub.c +@@ -0,0 +1,50 @@ ++/* $Id: auditstub.c,v 1.1 jfch Exp $ */ ++ ++/* ++ * Copyright 2010 Red Hat, Inc. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * 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. ++ * ++ * Red Hat author: Jan F. Chadima ++ */ ++ ++#include ++ ++void ++audit_unsupported(int n) ++{ ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++} ++ ++void ++audit_session_key_free(int ctos) ++{ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++} +diff --git a/auth-rsa.c b/auth-rsa.c +index ff7a132..1e12515 100644 +--- a/auth-rsa.c ++++ b/auth-rsa.c +@@ -93,7 +93,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) + { + u_char buf[32], mdbuf[16]; + struct ssh_digest_ctx *md; +- int len; ++ int len, rv; ++#ifdef SSH_AUDIT_EVENTS ++ char *fp; ++#endif + + /* don't allow short keys */ + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { +@@ -117,12 +120,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) + ssh_digest_free(md); + + /* Verify that the response is the original challenge. */ +- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { +- /* Wrong answer. */ +- return (0); ++ rv = timingsafe_bcmp(response, mdbuf, 16) == 0; ++ ++#ifdef SSH_AUDIT_EVENTS ++ fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { ++ debug("unsuccessful audit"); ++ rv = 0; + } +- /* Correct answer. */ +- return (1); ++ free(fp); ++#endif ++ ++ return rv; + } + + /* +diff --git a/auth.c b/auth.c +index 5a9acd3..7eba5d4 100644 +--- a/auth.c ++++ b/auth.c +@@ -642,9 +642,6 @@ getpwnamallow(const char *user) + record_failed_login(user, + get_canonical_hostname(options.use_dns), "ssh"); + #endif +-#ifdef SSH_AUDIT_EVENTS +- audit_event(SSH_INVALID_USER); +-#endif /* SSH_AUDIT_EVENTS */ + return (NULL); + } + if (!allowed_user(pw)) +diff --git a/auth.h b/auth.h +index 847cffd..19fbcf5 100644 +--- a/auth.h ++++ b/auth.h +@@ -187,6 +187,7 @@ void abandon_challenge_response(Authctxt *); + + char *expand_authorized_keys(const char *, struct passwd *pw); + char *authorized_principals_file(struct passwd *); ++int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); +@@ -204,6 +205,7 @@ Key *get_hostkey_private_by_type(int); + int get_hostkey_index(Key *); + int ssh1_session_key(BIGNUM *); + void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int); ++int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + + /* debug messages during authentication */ + void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index 41f1a3f..80d9802 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -138,7 +138,7 @@ userauth_hostbased(Authctxt *authctxt) + /* test for allowed key and correct signature */ + authenticated = 0; + if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && +- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), ++ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) + authenticated = 1; + +@@ -155,6 +155,18 @@ done: + return authenticated; + } + ++int ++hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) ++{ ++ int rv; ++ ++ rv = key_verify(key, sig, slen, data, datalen); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(0, &rv, key); ++#endif ++ return rv; ++} ++ + /* return 1 if given hostkey is allowed */ + int + hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index 269e642..110ec48 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -160,7 +160,7 @@ userauth_pubkey(Authctxt *authctxt) + /* test for correct signature */ + authenticated = 0; + if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && +- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), ++ PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) + authenticated = 1; + buffer_free(&b); +@@ -232,6 +232,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) + free(extra); + } + ++int ++user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) ++{ ++ int rv; ++ ++ rv = key_verify(key, sig, slen, data, datalen); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(1, &rv, key); ++#endif ++ return rv; ++} ++ + static int + match_principals_option(const char *principal_list, struct sshkey_cert *cert) + { +diff --git a/auth2.c b/auth2.c +index ec4ff8a..9e6e815 100644 +--- a/auth2.c ++++ b/auth2.c +@@ -250,9 +250,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) + } else { + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); +-#ifdef SSH_AUDIT_EVENTS +- PRIVSEP(audit_event(SSH_INVALID_USER)); +-#endif + } + #ifdef USE_PAM + if (options.use_pam) +diff --git a/cipher.c b/cipher.c +index 638ca2d..9cc7cf8 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -57,26 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_3des(void); + extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + #endif + +-struct sshcipher { +- char *name; +- int number; /* for ssh1 only */ +- u_int block_size; +- u_int key_len; +- u_int iv_len; /* defaults to block_size */ +- u_int auth_len; +- u_int discard_len; +- u_int flags; +-#define CFLAG_CBC (1<<0) +-#define CFLAG_CHACHAPOLY (1<<1) +-#define CFLAG_AESCTR (1<<2) +-#define CFLAG_NONE (1<<3) +-#ifdef WITH_OPENSSL +- const EVP_CIPHER *(*evptype)(void); +-#else +- void *ignored; +-#endif +-}; +- + static const struct sshcipher ciphers[] = { + #ifdef WITH_SSH1 + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, +diff --git a/cipher.h b/cipher.h +index de74c1e..26ed4cb 100644 +--- a/cipher.h ++++ b/cipher.h +@@ -62,7 +62,26 @@ + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + +-struct sshcipher; ++struct sshcipher { ++ char *name; ++ int number; /* for ssh1 only */ ++ u_int block_size; ++ u_int key_len; ++ u_int iv_len; /* defaults to block_size */ ++ u_int auth_len; ++ u_int discard_len; ++ u_int flags; ++#define CFLAG_CBC (1<<0) ++#define CFLAG_CHACHAPOLY (1<<1) ++#define CFLAG_AESCTR (1<<2) ++#define CFLAG_NONE (1<<3) ++#ifdef WITH_OPENSSL ++ const EVP_CIPHER *(*evptype)(void); ++#else ++ void *ignored; ++#endif ++}; ++ + struct sshcipher_ctx { + int plaintext; + int encrypt; +diff --git a/kex.c b/kex.c +index 4563920..e0cf3de 100644 +--- a/kex.c ++++ b/kex.c +@@ -52,6 +52,7 @@ + #include "monitor.h" + #include "roaming.h" + #include "digest.h" ++#include "audit.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -370,9 +371,13 @@ static void + choose_enc(Enc *enc, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(0); ++#endif + fatal("no matching cipher found: client %s server %s", + client, server); ++ } + if ((enc->cipher = cipher_by_name(name)) == NULL) + fatal("matching cipher is not supported: %s", name); + enc->name = name; +@@ -388,9 +393,13 @@ static void + choose_mac(Mac *mac, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(1); ++#endif + fatal("no matching mac found: client %s server %s", + client, server); ++ } + if (mac_setup(mac, name) < 0) + fatal("unsupported mac %s", name); + /* truncate the key */ +@@ -405,8 +414,12 @@ static void + choose_comp(Comp *comp, char *client, char *server) + { + char *name = match_list(client, server, NULL); +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(2); ++#endif + fatal("no matching comp found: client %s server %s", client, server); ++ } + if (strcmp(name, "zlib@openssh.com") == 0) { + comp->type = COMP_DELAYED; + } else if (strcmp(name, "zlib") == 0) { +@@ -522,9 +535,11 @@ kex_choose_conf(Kex *kex) + authlen == 0 ? newkeys->mac.name : "", + newkeys->comp.name); + } ++ + choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); ++ + need = dh_need = 0; + for (mode = 0; mode < MODE_MAX; mode++) { + newkeys = kex->newkeys[mode]; +@@ -536,11 +551,16 @@ kex_choose_conf(Kex *kex) + dh_need = MAX(dh_need, newkeys->enc.block_size); + dh_need = MAX(dh_need, newkeys->enc.iv_len); + dh_need = MAX(dh_need, newkeys->mac.key_len); ++ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); ++#endif + } + /* XXX need runden? */ + kex->we_need = need; + kex->dh_need = dh_need; + ++ + /* ignore the next message if the proposals do not match */ + if (first_kex_follows && !proposals_match(my, peer) && + !(datafellows & SSH_BUG_FIRSTKEX)) { +@@ -710,3 +730,34 @@ dump_digest(char *msg, u_char *digest, int len) + fprintf(stderr, "\n"); + } + #endif ++ ++static void ++enc_destroy(Enc *enc) ++{ ++ if (enc == NULL) ++ return; ++ ++ if (enc->key) { ++ memset(enc->key, 0, enc->key_len); ++ free(enc->key); ++ } ++ ++ if (enc->iv) { ++ memset(enc->iv, 0, enc->block_size); ++ free(enc->iv); ++ } ++ ++ memset(enc, 0, sizeof(*enc)); ++} ++ ++void ++newkeys_destroy(Newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ enc_destroy(&newkeys->enc); ++ mac_destroy(&newkeys->mac); ++ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); ++} ++ +diff --git a/kex.h b/kex.h +index 1c76c08..e015d27 100644 +--- a/kex.h ++++ b/kex.h +@@ -182,6 +182,8 @@ void kexgss_client(Kex *); + void kexgss_server(Kex *); + #endif + ++void newkeys_destroy(Newkeys *newkeys); ++ + void + kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); +diff --git a/key.h b/key.h +index e1a3625..4a90e1e 100644 +--- a/key.h ++++ b/key.h +@@ -52,6 +52,7 @@ typedef struct sshkey Key; + #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid + #define key_names_valid2 sshkey_names_valid2 + #define key_is_cert sshkey_is_cert ++#define key_is_private sshkey_is_private + #define key_type_plain sshkey_type_plain + #define key_cert_is_legacy sshkey_cert_is_legacy + #define key_curve_name_to_nid sshkey_curve_name_to_nid +diff --git a/mac.c b/mac.c +index 402dc98..fd07bf2 100644 +--- a/mac.c ++++ b/mac.c +@@ -223,6 +223,20 @@ mac_clear(Mac *mac) + mac->umac_ctx = NULL; + } + ++void ++mac_destroy(Mac *mac) ++{ ++ if (mac == NULL) ++ return; ++ ++ if (mac->key) { ++ memset(mac->key, 0, mac->key_len); ++ free(mac->key); ++ } ++ ++ memset(mac, 0, sizeof(*mac)); ++} ++ + /* XXX copied from ciphers_valid */ + #define MAC_SEP "," + int +diff --git a/mac.h b/mac.h +index fbe18c4..7dc7f43 100644 +--- a/mac.h ++++ b/mac.h +@@ -29,3 +29,4 @@ int mac_setup(Mac *, char *); + int mac_init(Mac *); + u_char *mac_compute(Mac *, u_int32_t, u_char *, int); + void mac_clear(Mac *); ++void mac_destroy(Mac *); +diff --git a/monitor.c b/monitor.c +index d97e640..07fa655 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -100,6 +100,7 @@ + #include "ssh2.h" + #include "roaming.h" + #include "authfd.h" ++#include "audit.h" + + #ifdef GSSAPI + static Gssctxt *gsscontext = NULL; +@@ -116,6 +117,8 @@ extern Buffer auth_debug; + extern int auth_debug_init; + extern Buffer loginmsg; + ++extern void destroy_sensitive_data(int); ++ + /* State exported from the child */ + + struct { +@@ -188,6 +191,11 @@ int mm_answer_gss_updatecreds(int, Buffer *); + #ifdef SSH_AUDIT_EVENTS + int mm_answer_audit_event(int, Buffer *); + int mm_answer_audit_command(int, Buffer *); ++int mm_answer_audit_end_command(int, Buffer *); ++int mm_answer_audit_unsupported_body(int, Buffer *); ++int mm_answer_audit_kex_body(int, Buffer *); ++int mm_answer_audit_session_key_free_body(int, Buffer *); ++int mm_answer_audit_server_key_free(int, Buffer *); + #endif + + static int monitor_read_log(struct monitor *); +@@ -247,6 +255,10 @@ struct mon_table mon_dispatch_proto20[] = { + #endif + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + #ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, +@@ -285,6 +297,11 @@ struct mon_table mon_dispatch_postauth20[] = { + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, + {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, ++ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + {0, 0, NULL} + }; +@@ -317,6 +334,10 @@ struct mon_table mon_dispatch_proto15[] = { + #endif + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + #endif /* WITH_SSH1 */ + {0, 0, NULL} +@@ -330,6 +351,11 @@ struct mon_table mon_dispatch_postauth15[] = { + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, + {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, ++ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + #endif /* WITH_SSH1 */ + {0, 0, NULL} +@@ -1416,9 +1442,11 @@ mm_answer_keyverify(int sock, Buffer *m) + Key *key; + u_char *signature, *data, *blob; + u_int signaturelen, datalen, bloblen; ++ int type = 0; + int verified = 0; + int valid_data = 0; + ++ type = buffer_get_int(m); + blob = buffer_get_string(m, &bloblen); + signature = buffer_get_string(m, &signaturelen); + data = buffer_get_string(m, &datalen); +@@ -1426,6 +1454,8 @@ mm_answer_keyverify(int sock, Buffer *m) + if (hostbased_cuser == NULL || hostbased_chost == NULL || + !monitor_allowed_key(blob, bloblen)) + fatal("%s: bad key, not previously allowed", __func__); ++ if (type != key_blobtype) ++ fatal("%s: bad key type", __func__); + + key = key_from_blob(blob, bloblen); + if (key == NULL) +@@ -1446,7 +1476,17 @@ mm_answer_keyverify(int sock, Buffer *m) + if (!valid_data) + fatal("%s: bad signature data blob", __func__); + +- verified = key_verify(key, signature, signaturelen, data, datalen); ++ switch (key_blobtype) { ++ case MM_USERKEY: ++ verified = user_key_verify(key, signature, signaturelen, data, datalen); ++ break; ++ case MM_HOSTKEY: ++ verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); ++ break; ++ default: ++ verified = 0; ++ break; ++ } + debug3("%s: key %p signature %s", + __func__, key, (verified == 1) ? "verified" : "unverified"); + +@@ -1499,6 +1539,12 @@ mm_session_close(Session *s) + debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); + session_pty_cleanup2(s); + } ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL) { ++ debug3("%s: command %d", __func__, s->command_handle); ++ session_end_command2(s); ++ } ++#endif + session_unused(s->self); + } + +@@ -1781,6 +1827,8 @@ mm_answer_term(int sock, Buffer *req) + sshpam_cleanup(); + #endif + ++ destroy_sensitive_data(0); ++ + while (waitpid(pmonitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); +@@ -1823,11 +1871,43 @@ mm_answer_audit_command(int socket, Buffer *m) + { + u_int len; + char *cmd; ++ Session *s; + + debug3("%s entering", __func__); + cmd = buffer_get_string(m, &len); ++ + /* sanity check command, if so how? */ +- audit_run_command(cmd); ++ s = session_new(); ++ if (s == NULL) ++ fatal("%s: error allocating a session", __func__); ++ s->command = cmd; ++ s->command_handle = audit_run_command(cmd); ++ ++ buffer_clear(m); ++ buffer_put_int(m, s->self); ++ ++ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); ++ ++ return (0); ++} ++ ++int ++mm_answer_audit_end_command(int socket, Buffer *m) ++{ ++ int handle; ++ u_int len; ++ char *cmd; ++ Session *s; ++ ++ debug3("%s entering", __func__); ++ handle = buffer_get_int(m); ++ cmd = buffer_get_string(m, &len); ++ ++ s = session_by_id(handle); ++ if (s == NULL || s->ttyfd != -1 || s->command == NULL || ++ strcmp(s->command, cmd) != 0) ++ fatal("%s: invalid handle", __func__); ++ mm_session_close(s); + free(cmd); + return (0); + } +@@ -1975,11 +2055,13 @@ mm_get_keystate(struct monitor *pmonitor) + + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + debug3("%s: Waiting for second key", __func__); + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + /* Now get sequence numbers for the packets */ +@@ -2025,6 +2107,21 @@ mm_get_keystate(struct monitor *pmonitor) + } + + buffer_free(&m); ++ ++#ifdef SSH_AUDIT_EVENTS ++ if (compat20) { ++ buffer_init(&m); ++ mm_request_receive_expect(pmonitor->m_sendfd, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); ++ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m); ++ buffer_free(&m); ++ } ++#endif ++ ++ /* Drain any buffered messages from the child */ ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) ++ ; ++ + } + + +@@ -2321,3 +2418,87 @@ mm_answer_gss_updatecreds(int socket, Buffer *m) { + + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++int ++mm_answer_audit_unsupported_body(int sock, Buffer *m) ++{ ++ int what; ++ ++ what = buffer_get_int(m); ++ ++ audit_unsupported_body(what); ++ ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_kex_body(int sock, Buffer *m) ++{ ++ int ctos, len; ++ char *cipher, *mac, *compress, *pfs; ++ pid_t pid; ++ uid_t uid; ++ ++ ctos = buffer_get_int(m); ++ cipher = buffer_get_string(m, &len); ++ mac = buffer_get_string(m, &len); ++ compress = buffer_get_string(m, &len); ++ pfs = buffer_get_string(m, &len); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); ++ ++ free(cipher); ++ free(mac); ++ free(compress); ++ free(pfs); ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_session_key_free_body(int sock, Buffer *m) ++{ ++ int ctos; ++ pid_t pid; ++ uid_t uid; ++ ++ ctos = buffer_get_int(m); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_session_key_free_body(ctos, pid, uid); ++ ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_server_key_free(int sock, Buffer *m) ++{ ++ int len; ++ char *fp; ++ pid_t pid; ++ uid_t uid; ++ ++ fp = buffer_get_string(m, &len); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_destroy_sensitive_data(fp, pid, uid); ++ ++ free(fp); ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m); ++ return 0; ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff --git a/monitor.h b/monitor.h +index 00c2028..cc8da6a 100644 +--- a/monitor.h ++++ b/monitor.h +@@ -69,7 +69,13 @@ enum monitor_reqtype { + MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, + MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, + MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, +- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, ++ MONITOR_REQ_AUDIT_EVENT = 112, ++ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, ++ MONITOR_REQ_AUDIT_END_COMMAND = 116, ++ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, ++ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, ++ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125 + + }; + +diff --git a/monitor_wrap.c b/monitor_wrap.c +index 7e991e6..ba4ecd7 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -456,7 +456,7 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) + */ + + int +-mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) + { + Buffer m; + u_char *blob; +@@ -470,6 +470,7 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) + return (0); + + buffer_init(&m); ++ buffer_put_int(&m, type); + buffer_put_string(&m, blob, len); + buffer_put_string(&m, sig, siglen); + buffer_put_string(&m, data, datalen); +@@ -487,6 +488,19 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) + return (verified); + } + ++int ++mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++{ ++ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); ++} ++ ++int ++mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++{ ++ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); ++} ++ ++ + /* Export key state after authentication */ + Newkeys * + mm_newkeys_from_blob(u_char *blob, int blen) +@@ -665,12 +679,14 @@ mm_send_keystate(struct monitor *monitor) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); ++ memset(blob, 0, bloblen); + free(blob); + + packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes); +@@ -1218,10 +1234,11 @@ mm_audit_event(ssh_audit_event_t event) + buffer_free(&m); + } + +-void ++int + mm_audit_run_command(const char *command) + { + Buffer m; ++ int handle; + + debug3("%s entering command %s", __func__, command); + +@@ -1229,6 +1246,26 @@ mm_audit_run_command(const char *command) + buffer_put_cstring(&m, command); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); ++ ++ handle = buffer_get_int(&m); ++ buffer_free(&m); ++ ++ return (handle); ++} ++ ++void ++mm_audit_end_command(int handle, const char *command) ++{ ++ Buffer m; ++ ++ debug3("%s entering command %s", __func__, command); ++ ++ buffer_init(&m); ++ buffer_put_int(&m, handle); ++ buffer_put_cstring(&m, command); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); + buffer_free(&m); + } + #endif /* SSH_AUDIT_EVENTS */ +@@ -1364,3 +1401,72 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) + + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++void ++mm_audit_unsupported_body(int what) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, what); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, ++ &m); ++ ++ buffer_free(&m); ++} ++ ++void ++mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, ++ uid_t uid) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, ctos); ++ buffer_put_cstring(&m, cipher); ++ buffer_put_cstring(&m, (mac ? mac : "")); ++ buffer_put_cstring(&m, compress); ++ buffer_put_cstring(&m, fps); ++ buffer_put_int64(&m, pid); ++ buffer_put_int64(&m, uid); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, ++ &m); ++ ++ buffer_free(&m); ++} ++ ++void ++mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, ctos); ++ buffer_put_int64(&m, pid); ++ buffer_put_int64(&m, uid); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, ++ &m); ++ buffer_free(&m); ++} ++ ++void ++mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_cstring(&m, fp); ++ buffer_put_int64(&m, pid); ++ buffer_put_int64(&m, uid); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, ++ &m); ++ buffer_free(&m); ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff --git a/monitor_wrap.h b/monitor_wrap.h +index 93929e0..e43109f 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char *, char *, Key *); + int mm_user_key_allowed(struct passwd *, Key *); + int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); + int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); + int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); + int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); + BIGNUM *mm_auth_rsa_generate_challenge(Key *); +@@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *); + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(ssh_audit_event_t); +-void mm_audit_run_command(const char *); ++int mm_audit_run_command(const char *); ++void mm_audit_end_command(int, const char *); ++void mm_audit_unsupported_body(int); ++void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); ++void mm_audit_session_key_free_body(int, pid_t, uid_t); ++void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); + #endif + + struct Session; +diff --git a/packet.c b/packet.c +index 9b7abd1..f1e00f7 100644 +--- a/packet.c ++++ b/packet.c +@@ -61,6 +61,7 @@ + #include + + #include "xmalloc.h" ++#include "audit.h" + #include "buffer.h" + #include "packet.h" + #include "crc32.h" +@@ -483,6 +484,13 @@ packet_get_connection_out(void) + return active_state->connection_out; + } + ++static int ++packet_state_has_keys (const struct session_state *state) ++{ ++ return state != NULL && ++ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); ++} ++ + /* Closes the connection and clears and frees internal data structures. */ + + void +@@ -491,13 +499,6 @@ packet_close(void) + if (!active_state->initialized) + return; + active_state->initialized = 0; +- if (active_state->connection_in == active_state->connection_out) { +- shutdown(active_state->connection_out, SHUT_RDWR); +- close(active_state->connection_out); +- } else { +- close(active_state->connection_in); +- close(active_state->connection_out); +- } + buffer_free(&active_state->input); + buffer_free(&active_state->output); + buffer_free(&active_state->outgoing_packet); +@@ -506,8 +507,18 @@ packet_close(void) + buffer_free(&active_state->compression_buffer); + buffer_compress_uninit(); + } +- cipher_cleanup(&active_state->send_context); +- cipher_cleanup(&active_state->receive_context); ++ if (packet_state_has_keys(active_state)) { ++ cipher_cleanup(&active_state->send_context); ++ cipher_cleanup(&active_state->receive_context); ++ audit_session_key_free(2); ++ } ++ if (active_state->connection_in == active_state->connection_out) { ++ shutdown(active_state->connection_out, SHUT_RDWR); ++ close(active_state->connection_out); ++ } else { ++ close(active_state->connection_in); ++ close(active_state->connection_out); ++ } + } + + /* Sets remote side protocol flags. */ +@@ -747,6 +758,25 @@ packet_send1(void) + */ + } + ++static void ++newkeys_destroy_and_free(Newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ free(newkeys->enc.name); ++ ++ if (newkeys->mac.enabled) { ++ mac_clear(&newkeys->mac); ++ free(newkeys->mac.name); ++ } ++ ++ free(newkeys->comp.name); ++ ++ newkeys_destroy(newkeys); ++ free(newkeys); ++} ++ + void + set_newkeys(int mode) + { +@@ -772,6 +802,7 @@ set_newkeys(int mode) + } + if (active_state->newkeys[mode] != NULL) { + debug("set_newkeys: rekeying"); ++ audit_session_key_free(mode); + cipher_cleanup(cc); + enc = &active_state->newkeys[mode]->enc; + mac = &active_state->newkeys[mode]->mac; +@@ -2025,6 +2056,47 @@ packet_get_newkeys(int mode) + return (void *)active_state->newkeys[mode]; + } + ++static void ++packet_destroy_state(struct session_state *state) ++{ ++ if (state == NULL) ++ return; ++ ++ cipher_cleanup(&state->receive_context); ++ cipher_cleanup(&state->send_context); ++ ++ buffer_free(&state->input); ++ buffer_free(&state->output); ++ buffer_free(&state->outgoing_packet); ++ buffer_free(&state->incoming_packet); ++ buffer_free(&state->compression_buffer); ++ newkeys_destroy_and_free(state->newkeys[MODE_IN]); ++ state->newkeys[MODE_IN] = NULL; ++ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); ++ state->newkeys[MODE_OUT] = NULL; ++ mac_destroy(state->packet_discard_mac); ++// TAILQ_HEAD(, packet) outgoing; ++// memset(state, 0, sizeof(state)); ++} ++ ++void ++packet_destroy_all(int audit_it, int privsep) ++{ ++ if (audit_it) ++ audit_it = packet_state_has_keys (active_state) || ++ packet_state_has_keys (backup_state); ++ packet_destroy_state(active_state); ++ packet_destroy_state(backup_state); ++ if (audit_it) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ audit_session_key_free(2); ++ else ++ audit_session_key_free_body(2, getpid(), getuid()); ++#endif ++ } ++} ++ + /* + * Save the state for the real connection, and use a separate state when + * resuming a suspended connection. +@@ -2032,18 +2104,12 @@ packet_get_newkeys(int mode) + void + packet_backup_state(void) + { +- struct session_state *tmp; +- + close(active_state->connection_in); + active_state->connection_in = -1; + close(active_state->connection_out); + active_state->connection_out = -1; +- if (backup_state) +- tmp = backup_state; +- else +- tmp = alloc_session_state(); + backup_state = active_state; +- active_state = tmp; ++ active_state = alloc_session_state(); + } + + /* +@@ -2060,9 +2126,7 @@ packet_restore_state(void) + backup_state = active_state; + active_state = tmp; + active_state->connection_in = backup_state->connection_in; +- backup_state->connection_in = -1; + active_state->connection_out = backup_state->connection_out; +- backup_state->connection_out = -1; + len = buffer_len(&backup_state->input); + if (len > 0) { + buf = buffer_ptr(&backup_state->input); +@@ -2070,6 +2134,11 @@ packet_restore_state(void) + buffer_clear(&backup_state->input); + add_recv_bytes(len); + } ++ backup_state->connection_in = -1; ++ backup_state->connection_out = -1; ++ packet_destroy_state(backup_state); ++ free(backup_state); ++ backup_state = NULL; + } + + /* Reset after_authentication and reset compression in post-auth privsep */ +diff --git a/packet.h b/packet.h +index e7b5fcb..45a6ce6 100644 +--- a/packet.h ++++ b/packet.h +@@ -125,4 +125,5 @@ void packet_set_postauth(void); + void *packet_get_input(void); + void *packet_get_output(void); + ++void packet_destroy_all(int, int); + #endif /* PACKET_H */ +diff --git a/session.c b/session.c +index 40a681e..acd87d5 100644 +--- a/session.c ++++ b/session.c +@@ -138,7 +138,7 @@ extern int log_stderr; + extern int debug_flag; + extern u_int utmp_len; + extern int startup_pipe; +-extern void destroy_sensitive_data(void); ++extern void destroy_sensitive_data(int); + extern Buffer loginmsg; + + /* original command from peer. */ +@@ -730,6 +730,14 @@ do_exec_pty(Session *s, const char *command) + /* Parent. Close the slave side of the pseudo tty. */ + close(ttyfd); + ++#ifndef HAVE_OSF_SIA ++ /* do_login in the child did not affect state in this process, ++ compensate. From an architectural standpoint, this is extremely ++ ugly. */ ++ if (!(options.use_login && command == NULL)) ++ audit_count_session_open(); ++#endif ++ + /* Enter interactive session. */ + s->ptymaster = ptymaster; + packet_set_interactive(1, +@@ -852,15 +860,19 @@ do_exec(Session *s, const char *command) + get_remote_port()); + + #ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL || s->command_handle != -1) ++ fatal("do_exec: command already set"); + if (command != NULL) +- PRIVSEP(audit_run_command(command)); ++ s->command = xstrdup(command); + else if (s->ttyfd == -1) { + char *shell = s->pw->pw_shell; + + if (shell[0] == '\0') /* empty shell means /bin/sh */ + shell =_PATH_BSHELL; +- PRIVSEP(audit_run_command(shell)); ++ s->command = xstrdup(shell); + } ++ if (s->command != NULL) ++ s->command_handle = PRIVSEP(audit_run_command(s->command)); + #endif + if (s->ttyfd != -1) + ret = do_exec_pty(s, command); +@@ -1703,7 +1715,10 @@ do_child(Session *s, const char *command) + int r = 0; + + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(1); ++ /* Don't audit this - both us and the parent would be talking to the ++ monitor over a single socket, with no synchronization. */ ++ packet_destroy_all(0, 1); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { +@@ -1933,6 +1948,7 @@ session_unused(int id) + sessions[id].ttyfd = -1; + sessions[id].ptymaster = -1; + sessions[id].x11_chanids = NULL; ++ sessions[id].command_handle = -1; + sessions[id].next_unused = sessions_first_unused; + sessions_first_unused = id; + } +@@ -2015,6 +2031,19 @@ session_open(Authctxt *authctxt, int chanid) + } + + Session * ++session_by_id(int id) ++{ ++ if (id >= 0 && id < sessions_nalloc) { ++ Session *s = &sessions[id]; ++ if (s->used) ++ return s; ++ } ++ debug("session_by_id: unknown id %d", id); ++ session_dump(); ++ return NULL; ++} ++ ++Session * + session_by_tty(char *tty) + { + int i; +@@ -2531,6 +2560,30 @@ session_exit_message(Session *s, int status) + chan_write_failed(c); + } + ++#ifdef SSH_AUDIT_EVENTS ++void ++session_end_command2(Session *s) ++{ ++ if (s->command != NULL) { ++ audit_end_command(s->command_handle, s->command); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++ ++static void ++session_end_command(Session *s) ++{ ++ if (s->command != NULL) { ++ PRIVSEP(audit_end_command(s->command_handle, s->command)); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++#endif ++ + void + session_close(Session *s) + { +@@ -2539,6 +2592,10 @@ session_close(Session *s) + debug("session_close: session %d pid %ld", s->self, (long)s->pid); + if (s->ttyfd != -1) + session_pty_cleanup(s); ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command) ++ session_end_command(s); ++#endif + free(s->term); + free(s->display); + free(s->x11_chanids); +@@ -2753,6 +2810,15 @@ do_authenticated2(Authctxt *authctxt) + server_loop2(authctxt); + } + ++static void ++do_cleanup_one_session(Session *s) ++{ ++ session_pty_cleanup2(s); ++#ifdef SSH_AUDIT_EVENTS ++ session_end_command2(s); ++#endif ++} ++ + void + do_cleanup(Authctxt *authctxt) + { +@@ -2801,5 +2867,5 @@ do_cleanup(Authctxt *authctxt) + * or if running in monitor. + */ + if (!use_privsep || mm_is_monitor()) +- session_destroy_all(session_pty_cleanup2); ++ session_destroy_all(do_cleanup_one_session); + } +diff --git a/session.h b/session.h +index 6a2f35e..e9b312e 100644 +--- a/session.h ++++ b/session.h +@@ -61,6 +61,12 @@ struct Session { + char *name; + char *val; + } *env; ++ ++ /* exec */ ++#ifdef SSH_AUDIT_EVENTS ++ int command_handle; ++ char *command; ++#endif + }; + + void do_authenticated(Authctxt *); +@@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); + void session_close_by_channel(int, void *); + void session_destroy_all(void (*)(Session *)); + void session_pty_cleanup2(Session *); ++void session_end_command2(Session *); + + Session *session_new(void); ++Session *session_by_id(int); + Session *session_by_tty(char *); + void session_close(Session *); + void do_setusercontext(struct passwd *); +diff --git a/sshd.c b/sshd.c +index ca55d7f..db23ce2 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -120,6 +120,7 @@ + #endif + #include "monitor_wrap.h" + #include "roaming.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "version.h" + +@@ -254,7 +255,7 @@ Buffer loginmsg; + struct passwd *privsep_pw = NULL; + + /* Prototypes for various functions defined later in this file. */ +-void destroy_sensitive_data(void); ++void destroy_sensitive_data(int); + void demote_sensitive_data(void); + + #ifdef WITH_SSH1 +@@ -275,6 +276,15 @@ close_listen_socks(void) + num_listen_socks = -1; + } + ++/* ++ * Is this process listening for clients (i.e. not specific to any specific ++ * client connection?) ++ */ ++int listening_for_clients(void) ++{ ++ return num_listen_socks > 0; ++} ++ + static void + close_startup_pipes(void) + { +@@ -554,22 +564,45 @@ sshd_exchange_identification(int sock_in, int sock_out) + } + } + +-/* Destroy the host and server keys. They will no longer be needed. */ ++/* ++ * Destroy the host and server keys. They will no longer be needed. Careful, ++ * this can be called from cleanup_exit() - i.e. from just about anywhere. ++ */ + void +-destroy_sensitive_data(void) ++destroy_sensitive_data(int privsep) + { + int i; ++ pid_t pid; ++ uid_t uid; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } ++ pid = getpid(); ++ uid = getuid(); + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (key_is_private(sensitive_data.host_keys[i])) ++ fp = key_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); ++ else ++ fp = NULL; + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; ++ if (fp != NULL) { ++ if (privsep) ++ PRIVSEP(audit_destroy_sensitive_data(fp, ++ pid, uid)); ++ else ++ audit_destroy_sensitive_data(fp, ++ pid, uid); ++ free(fp); ++ } + } +- if (sensitive_data.host_certificates[i]) { ++ if (sensitive_data.host_certificates ++ && sensitive_data.host_certificates[i]) { + key_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } +@@ -583,6 +616,8 @@ void + demote_sensitive_data(void) + { + Key *tmp; ++ pid_t pid; ++ uid_t uid; + int i; + + if (sensitive_data.server_key) { +@@ -591,13 +626,25 @@ demote_sensitive_data(void) + sensitive_data.server_key = tmp; + } + ++ pid = getpid(); ++ uid = getuid(); + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (key_is_private(sensitive_data.host_keys[i])) ++ fp = key_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); ++ else ++ fp = NULL; + tmp = key_demote(sensitive_data.host_keys[i]); + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = tmp; + if (tmp->type == KEY_RSA1) + sensitive_data.ssh1_host_key = tmp; ++ if (fp != NULL) { ++ audit_destroy_sensitive_data(fp, pid, uid); ++ free(fp); ++ } + } + /* Certs do not need demotion */ + } +@@ -667,7 +714,7 @@ privsep_preauth(Authctxt *authctxt) + + if (use_privsep == PRIVSEP_ON) + box = ssh_sandbox_init(pmonitor); +- pid = fork(); ++ pmonitor->m_pid = pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { +@@ -721,6 +768,8 @@ privsep_preauth(Authctxt *authctxt) + } + } + ++extern Newkeys *current_keys[]; ++ + static void + privsep_postauth(Authctxt *authctxt) + { +@@ -745,6 +794,10 @@ privsep_postauth(Authctxt *authctxt) + else if (pmonitor->m_pid != 0) { + verbose("User child is on pid %ld", (long)pmonitor->m_pid); + buffer_clear(&loginmsg); ++ newkeys_destroy(current_keys[MODE_OUT]); ++ newkeys_destroy(current_keys[MODE_IN]); ++ audit_session_key_free_body(2, getpid(), getuid()); ++ packet_destroy_all(0, 0); + monitor_child_postauth(pmonitor); + + /* NEVERREACHED */ +@@ -1222,6 +1275,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ destroy_sensitive_data(0); + close_listen_socks(); + unlink(options.pid_file); + exit(received_sigterm == SIGTERM ? 0 : 255); +@@ -2141,6 +2195,7 @@ main(int ac, char **av) + */ + if (use_privsep) { + mm_send_keystate(pmonitor); ++ packet_destroy_all(1, 1); + exit(0); + } + +@@ -2186,7 +2241,7 @@ main(int ac, char **av) + privsep_postauth(authctxt); + /* the monitor process [priv] will not return */ + if (!compat20) +- destroy_sensitive_data(); ++ destroy_sensitive_data(0); + } + + packet_set_timeout(options.client_alive_interval, +@@ -2196,6 +2251,9 @@ main(int ac, char **av) + do_authenticated(authctxt); + + /* The connection has been terminated. */ ++ packet_destroy_all(1, 1); ++ destroy_sensitive_data(1); ++ + packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); + packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); + verbose("Transferred: sent %llu, received %llu bytes", +@@ -2355,6 +2413,10 @@ do_ssh1_kex(void) + if (cookie[i] != packet_get_char()) + packet_disconnect("IP Spoofing check bytes do not match."); + ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(2, cipher_name(cipher_type), "crc", "none", "none"); ++#endif ++ + debug("Encryption type: %.200s", cipher_name(cipher_type)); + + /* Get the encrypted integer. */ +@@ -2427,7 +2489,7 @@ do_ssh1_kex(void) + session_id[i] = session_key[i] ^ session_key[i + 16]; + } + /* Destroy the private and public keys. No longer. */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(0); + + if (use_privsep) + mm_ssh1_session_id(session_id); +@@ -2598,6 +2660,16 @@ do_ssh2_kex(void) + void + cleanup_exit(int i) + { ++ static int in_cleanup = 0; ++ int is_privsep_child; ++ ++ /* cleanup_exit can be called at the very least from the privsep ++ wrappers used for auditing. Make sure we don't recurse ++ indefinitely. */ ++ if (in_cleanup) ++ _exit(i); ++ in_cleanup = 1; ++ + if (the_authctxt) { + do_cleanup(the_authctxt); + if (use_privsep && privsep_is_preauth && +@@ -2609,9 +2681,14 @@ cleanup_exit(int i) + pmonitor->m_pid, strerror(errno)); + } + } ++ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; ++ if (sensitive_data.host_keys != NULL) ++ destroy_sensitive_data(is_privsep_child); ++ packet_destroy_all(1, is_privsep_child); + #ifdef SSH_AUDIT_EVENTS + /* done after do_cleanup so it can cancel the PAM auth 'thread' */ +- if (!use_privsep || mm_is_monitor()) ++ if ((the_authctxt == NULL || !the_authctxt->authenticated) && ++ (!use_privsep || mm_is_monitor())) + audit_event(SSH_CONNECTION_ABANDON); + #endif + _exit(i); +diff --git a/sshkey.c b/sshkey.c +index 70df758..f078e11 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -291,6 +291,33 @@ sshkey_type_is_valid_ca(int type) + } + + int ++sshkey_is_private(const struct sshkey *k) ++{ ++ switch (k->type) { ++ case KEY_RSA_CERT_V00: ++ case KEY_RSA_CERT: ++ case KEY_RSA1: ++ case KEY_RSA: ++ return k->rsa->d != NULL; ++ case KEY_DSA_CERT_V00: ++ case KEY_DSA_CERT: ++ case KEY_DSA: ++ return k->dsa->priv_key != NULL; ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: ++ return EC_KEY_get0_private_key(k->ecdsa) != NULL; ++#endif ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } ++} ++ ++int + sshkey_is_cert(const struct sshkey *k) + { + if (k == NULL) +diff --git a/sshkey.h b/sshkey.h +index 4554b09..226a494 100644 +--- a/sshkey.h ++++ b/sshkey.h +@@ -134,6 +134,7 @@ u_int sshkey_size(const struct sshkey *); + int sshkey_generate(int type, u_int bits, struct sshkey **keyp); + int sshkey_from_private(const struct sshkey *, struct sshkey **); + int sshkey_type_from_name(const char *); ++int sshkey_is_private(const struct sshkey *); + int sshkey_is_cert(const struct sshkey *); + int sshkey_type_is_cert(int); + int sshkey_type_plain(int); diff --git a/openssh-6.7p1-fingerprint.patch b/openssh-6.7p1-fingerprint.patch index da798dd..d29fc9b 100644 --- a/openssh-6.7p1-fingerprint.patch +++ b/openssh-6.7p1-fingerprint.patch @@ -1,13 +1,47 @@ -diff -up openssh-6.7p1/auth2-hostbased.c.fingerprint openssh-6.7p1/auth2-hostbased.c ---- openssh-6.7p1/auth2-hostbased.c.fingerprint 2014-07-18 06:11:25.000000000 +0200 -+++ openssh-6.7p1/auth2-hostbased.c 2014-12-22 13:10:57.961878113 +0100 +diff --git a/auth-rsa.c b/auth-rsa.c +index e9f4ede..ff7a132 100644 +--- a/auth-rsa.c ++++ b/auth-rsa.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */ ++/* $OpenBSD: auth-rsa.c,v 1.89 2014/12/21 22:27:56 djm Exp $ */ + /* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +@@ -236,7 +236,8 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file, + "actual %d vs. announced %d.", + file, linenum, BN_num_bits(key->rsa->n), bits); + +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, options.fingerprint_hash, ++ SSH_FP_DEFAULT); + debug("matching key found: file %s, line %lu %s %s", + file, linenum, key_type(key), fp); + free(fp); +diff --git a/auth.c b/auth.c +index 5e60682..5a9acd3 100644 +--- a/auth.c ++++ b/auth.c +@@ -702,7 +702,7 @@ auth_key_is_revoked(Key *key) + case 1: + revoked: + /* Key revoked */ +- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ key_fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); + error("WARNING: authentication attempt with a revoked " + "%s key %s ", key_type(key), key_fp); + free(key_fp); +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index 6787e4c..b7ae353 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.19 2014/12/21 22:27:56 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * -@@ -208,13 +208,14 @@ hostbased_key_allowed(struct passwd *pw, +@@ -208,13 +208,14 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, if (host_status == HOST_OK) { if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, @@ -24,10 +58,11 @@ diff -up openssh-6.7p1/auth2-hostbased.c.fingerprint openssh-6.7p1/auth2-hostbas verbose("Accepted %s public key %s from %s@%s", key_type(key), fp, cuser, lookup); } -diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c ---- openssh-6.7p1/auth2-pubkey.c.fingerprint 2014-07-18 06:11:25.000000000 +0200 -+++ openssh-6.7p1/auth2-pubkey.c 2014-12-22 13:13:56.446258343 +0100 -@@ -213,7 +213,7 @@ pubkey_auth_info(Authctxt *authctxt, con +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index f3ca965..3f4f789 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -213,7 +213,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, @@ -36,7 +71,7 @@ diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", key_type(key), key->cert->key_id, (unsigned long long)key->cert->serial, -@@ -221,7 +221,8 @@ pubkey_auth_info(Authctxt *authctxt, con +@@ -221,7 +221,8 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); } else { @@ -46,7 +81,7 @@ diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c auth_info(authctxt, "%s %s%s%s", key_type(key), fp, extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); -@@ -365,8 +366,8 @@ check_authkeys_file(FILE *f, char *file, +@@ -365,8 +366,8 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) continue; if (!key_is_cert_authority) continue; @@ -57,7 +92,7 @@ diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* -@@ -406,7 +407,8 @@ check_authkeys_file(FILE *f, char *file, +@@ -406,7 +407,8 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) if (key_is_cert_authority) continue; found_key = 1; @@ -67,7 +102,7 @@ diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c debug("matching key found: file %s, line %lu %s %s", file, linenum, key_type(found), fp); free(fp); -@@ -432,7 +434,7 @@ user_cert_trusted_ca(struct passwd *pw, +@@ -432,7 +434,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) return 0; ca_fp = key_fingerprint(key->cert->signature_key, @@ -76,62 +111,10 @@ diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c if (key_in_file(key->cert->signature_key, options.trusted_user_ca_keys, 1) != 1) { -diff -up openssh-6.7p1/auth.c.fingerprint openssh-6.7p1/auth.c ---- openssh-6.7p1/auth.c.fingerprint 2014-12-22 13:10:57.961878113 +0100 -+++ openssh-6.7p1/auth.c 2014-12-22 13:27:18.105463774 +0100 -@@ -702,7 +702,7 @@ auth_key_is_revoked(Key *key) - case 1: - revoked: - /* Key revoked */ -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); - error("WARNING: authentication attempt with a revoked " - "%s key %s ", key_type(key), key_fp); - free(key_fp); -diff -up openssh-6.7p1/auth-rsa.c.fingerprint openssh-6.7p1/auth-rsa.c ---- openssh-6.7p1/auth-rsa.c.fingerprint 2014-07-18 06:11:25.000000000 +0200 -+++ openssh-6.7p1/auth-rsa.c 2014-12-22 13:10:57.960878116 +0100 -@@ -1,4 +1,4 @@ --/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */ -+/* $OpenBSD: auth-rsa.c,v 1.89 2014/12/21 22:27:56 djm Exp $ */ - /* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland -@@ -236,7 +236,8 @@ rsa_key_allowed_in_file(struct passwd *p - "actual %d vs. announced %d.", - file, linenum, BN_num_bits(key->rsa->n), bits); - -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(key, options.fingerprint_hash, -+ SSH_FP_DEFAULT); - debug("matching key found: file %s, line %lu %s %s", - file, linenum, key_type(key), fp); - free(fp); -diff -up openssh-6.7p1/digest.h.fingerprint openssh-6.7p1/digest.h ---- openssh-6.7p1/digest.h.fingerprint 2014-07-03 13:25:04.000000000 +0200 -+++ openssh-6.7p1/digest.h 2014-12-22 13:10:57.961878113 +0100 -@@ -1,4 +1,4 @@ --/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */ -+/* $OpenBSD: digest.h,v 1.7 2014/12/21 22:27:56 djm Exp $ */ - /* - * Copyright (c) 2013 Damien Miller - * -@@ -33,6 +33,12 @@ - struct sshbuf; - struct ssh_digest_ctx; - -+/* Looks up a digest algorithm by name */ -+int ssh_digest_alg_by_name(const char *name); -+ -+/* Returns the algorithm name for a digest identifier */ -+const char *ssh_digest_alg_name(int alg); -+ - /* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ - size_t ssh_digest_bytes(int alg); - -diff -up openssh-6.7p1/digest-libc.c.fingerprint openssh-6.7p1/digest-libc.c ---- openssh-6.7p1/digest-libc.c.fingerprint 2014-07-02 07:28:03.000000000 +0200 -+++ openssh-6.7p1/digest-libc.c 2014-12-22 13:10:57.961878113 +0100 +diff --git a/digest-libc.c b/digest-libc.c +index 1b4423a..169ded0 100644 +--- a/digest-libc.c ++++ b/digest-libc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */ +/* $OpenBSD: digest-libc.c,v 1.4 2014/12/21 22:27:56 djm Exp $ */ @@ -165,9 +148,10 @@ diff -up openssh-6.7p1/digest-libc.c.fingerprint openssh-6.7p1/digest-libc.c size_t ssh_digest_bytes(int alg) { -diff -up openssh-6.7p1/digest-openssl.c.fingerprint openssh-6.7p1/digest-openssl.c ---- openssh-6.7p1/digest-openssl.c.fingerprint 2014-07-17 01:01:26.000000000 +0200 -+++ openssh-6.7p1/digest-openssl.c 2014-12-22 13:10:57.961878113 +0100 +diff --git a/digest-openssl.c b/digest-openssl.c +index 02b1703..bb58ff2 100644 +--- a/digest-openssl.c ++++ b/digest-openssl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: digest-openssl.c,v 1.4 2014/07/03 03:26:43 djm Exp $ */ +/* $OpenBSD: digest-openssl.c,v 1.5 2014/12/21 22:27:56 djm Exp $ */ @@ -201,9 +185,33 @@ diff -up openssh-6.7p1/digest-openssl.c.fingerprint openssh-6.7p1/digest-openssl size_t ssh_digest_bytes(int alg) { -diff -up openssh-6.7p1/dns.c.fingerprint openssh-6.7p1/dns.c ---- openssh-6.7p1/dns.c.fingerprint 2014-07-02 07:28:03.000000000 +0200 -+++ openssh-6.7p1/dns.c 2014-12-22 13:10:57.962878109 +0100 +diff --git a/digest.h b/digest.h +index 6afb197..3fe0734 100644 +--- a/digest.h ++++ b/digest.h +@@ -1,4 +1,4 @@ +-/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */ ++/* $OpenBSD: digest.h,v 1.7 2014/12/21 22:27:56 djm Exp $ */ + /* + * Copyright (c) 2013 Damien Miller + * +@@ -33,6 +33,12 @@ + struct sshbuf; + struct ssh_digest_ctx; + ++/* Looks up a digest algorithm by name */ ++int ssh_digest_alg_by_name(const char *name); ++ ++/* Returns the algorithm name for a digest identifier */ ++const char *ssh_digest_alg_name(int alg); ++ + /* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ + size_t ssh_digest_bytes(int alg); + +diff --git a/dns.c b/dns.c +index c4d073c..4b8ae44 100644 +--- a/dns.c ++++ b/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */ +/* $OpenBSD: dns.c,v 1.32 2014/12/21 22:27:56 djm Exp $ */ @@ -218,7 +226,7 @@ diff -up openssh-6.7p1/dns.c.fingerprint openssh-6.7p1/dns.c static const char *errset_text[] = { "success", /* 0 ERRSET_SUCCESS */ -@@ -80,7 +81,7 @@ dns_read_key(u_int8_t *algorithm, u_int8 +@@ -80,7 +81,7 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, u_char **digest, u_int *digest_len, Key *key) { int success = 0; @@ -227,7 +235,7 @@ diff -up openssh-6.7p1/dns.c.fingerprint openssh-6.7p1/dns.c switch (key->type) { case KEY_RSA: -@@ -110,17 +111,17 @@ dns_read_key(u_int8_t *algorithm, u_int8 +@@ -110,17 +111,17 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, switch (*digest_type) { case SSHFP_HASH_SHA1: @@ -248,9 +256,10 @@ diff -up openssh-6.7p1/dns.c.fingerprint openssh-6.7p1/dns.c if (*digest == NULL) fatal("dns_read_key: null from key_fingerprint_raw()"); success = 1; -diff -up openssh-6.7p1/key.c.fingerprint openssh-6.7p1/key.c ---- openssh-6.7p1/key.c.fingerprint 2014-07-23 01:40:47.000000000 +0200 -+++ openssh-6.7p1/key.c 2014-12-22 13:10:57.962878109 +0100 +diff --git a/key.c b/key.c +index 2060761..780be1c 100644 +--- a/key.c ++++ b/key.c @@ -40,8 +40,7 @@ key_new_private(int type) } @@ -261,7 +270,7 @@ diff -up openssh-6.7p1/key.c.fingerprint openssh-6.7p1/key.c { u_char *ret = NULL; size_t dlen; -@@ -49,7 +48,7 @@ key_fingerprint_raw(const Key *k, enum f +@@ -49,7 +48,7 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type, if (dgst_raw_length != NULL) *dgst_raw_length = 0; @@ -270,9 +279,10 @@ diff -up openssh-6.7p1/key.c.fingerprint openssh-6.7p1/key.c fatal("%s: %s", __func__, ssh_err(r)); if (dlen > INT_MAX) fatal("%s: giant len %zu", __func__, dlen); -diff -up openssh-6.7p1/key.h.fingerprint openssh-6.7p1/key.h ---- openssh-6.7p1/key.h.fingerprint 2014-08-21 02:48:41.000000000 +0200 -+++ openssh-6.7p1/key.h 2014-12-22 13:10:57.962878109 +0100 +diff --git a/key.h b/key.h +index c6401a5..e1a3625 100644 +--- a/key.h ++++ b/key.h @@ -67,7 +67,7 @@ void key_add_private(Key *); Key *key_new_private(int); void key_free(Key *); @@ -282,9 +292,10 @@ diff -up openssh-6.7p1/key.h.fingerprint openssh-6.7p1/key.h int key_write(const Key *, FILE *); int key_read(Key *, char **); -diff -up openssh-6.7p1/krl.c.fingerprint openssh-6.7p1/krl.c ---- openssh-6.7p1/krl.c.fingerprint 2014-12-22 13:10:57.962878109 +0100 -+++ openssh-6.7p1/krl.c 2014-12-22 13:24:45.969002948 +0100 +diff --git a/krl.c b/krl.c +index eb31df9..4abed7e 100644 +--- a/krl.c ++++ b/krl.c @@ -36,6 +36,7 @@ #include "misc.h" #include "log.h" @@ -293,7 +304,7 @@ diff -up openssh-6.7p1/krl.c.fingerprint openssh-6.7p1/krl.c #include "krl.h" -@@ -406,7 +407,7 @@ ssh_krl_revoke_key_sha1(struct ssh_krl * +@@ -406,7 +407,7 @@ ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const Key *key) u_int len; debug3("%s: revoke type %s by sha1", __func__, key_type(key)); @@ -302,7 +313,7 @@ diff -up openssh-6.7p1/krl.c.fingerprint openssh-6.7p1/krl.c return -1; return revoke_blob(&krl->revoked_sha1s, blob, len); } -@@ -1119,7 +1120,7 @@ is_key_revoked(struct ssh_krl *krl, cons +@@ -1119,7 +1120,7 @@ is_key_revoked(struct ssh_krl *krl, const Key *key) /* Check explicitly revoked hashes first */ memset(&rb, 0, sizeof(rb)); @@ -311,9 +322,10 @@ diff -up openssh-6.7p1/krl.c.fingerprint openssh-6.7p1/krl.c return -1; erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); free(rb.blob); -diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c ---- openssh-6.7p1/readconf.c.fingerprint 2014-07-18 06:11:26.000000000 +0200 -+++ openssh-6.7p1/readconf.c 2014-12-22 13:20:33.488879658 +0100 +diff --git a/readconf.c b/readconf.c +index 7948ce1..3f5c58b 100644 +--- a/readconf.c ++++ b/readconf.c @@ -56,6 +56,7 @@ #include "kex.h" #include "mac.h" @@ -338,17 +350,7 @@ diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c { "ignoreunknown", oIgnoreUnknown }, { NULL, oBadOption } -@@ -1097,6 +1100,9 @@ parse_int: - options->hostkeyalgorithms = xstrdup(arg); - break; - -+ case oFingerprintHash: -+ return ssh_digest_alg_name(val); -+ - case oProtocol: - intptr = &options->protocol; - arg = strdelim(&s); -@@ -1433,6 +1439,18 @@ parse_int: +@@ -1433,6 +1436,18 @@ parse_int: intptr = &options->fwd_opts.streamlocal_bind_unlink; goto parse_flag; @@ -367,7 +369,7 @@ diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); -@@ -1609,6 +1627,7 @@ initialize_options(Options * options) +@@ -1609,6 +1624,7 @@ initialize_options(Options * options) options->canonicalize_max_dots = -1; options->canonicalize_fallback_local = -1; options->canonicalize_hostname = -1; @@ -375,7 +377,7 @@ diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c } /* -@@ -1786,6 +1805,9 @@ fill_default_options(Options * options) +@@ -1786,6 +1802,9 @@ fill_default_options(Options * options) options->canonicalize_fallback_local = 1; if (options->canonicalize_hostname == -1) options->canonicalize_hostname = SSH_CANONICALISE_NO; @@ -385,9 +387,10 @@ diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c #define CLEAR_ON_NONE(v) \ do { \ if (option_clear_or_none(v)) { \ -diff -up openssh-6.7p1/readconf.h.fingerprint openssh-6.7p1/readconf.h ---- openssh-6.7p1/readconf.h.fingerprint 2014-12-22 13:10:57.963878106 +0100 -+++ openssh-6.7p1/readconf.h 2014-12-22 13:14:24.075162395 +0100 +diff --git a/readconf.h b/readconf.h +index 0b9cb77..a028306 100644 +--- a/readconf.h ++++ b/readconf.h @@ -144,6 +144,8 @@ typedef struct { int num_permitted_cnames; struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; @@ -397,9 +400,299 @@ diff -up openssh-6.7p1/readconf.h.fingerprint openssh-6.7p1/readconf.h char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ } Options; -diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c ---- openssh-6.7p1/servconf.c.fingerprint 2014-07-18 06:11:26.000000000 +0200 -+++ openssh-6.7p1/servconf.c 2014-12-22 13:25:22.626875655 +0100 +diff --git a/regress/Makefile b/regress/Makefile +index 3feb7a9..2905a0d 100644 +--- a/regress/Makefile ++++ b/regress/Makefile +@@ -1,6 +1,6 @@ +-# $OpenBSD: Makefile,v 1.70 2014/06/24 01:14:17 djm Exp $ ++# $OpenBSD: Makefile,v 1.71 2014/12/22 02:15:52 djm Exp $ + +-REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec ++REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t-exec + tests: $(REGRESS_TARGETS) + + # Interop tests are not run by default +@@ -119,7 +119,7 @@ t3: + ${TEST_SSH_SSHKEYGEN} -if $(OBJ)/t3.out | diff - ${.CURDIR}/rsa_openssh.pub + + t4: +- ${TEST_SSH_SSHKEYGEN} -lf ${.CURDIR}/rsa_openssh.pub |\ ++ ${TEST_SSH_SSHKEYGEN} -E md5 -lf ${.CURDIR}/rsa_openssh.pub |\ + awk '{print $$2}' | diff - ${.CURDIR}/t4.ok + + t5: +@@ -164,6 +164,10 @@ t10: $(OBJ)/t10.out + ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t10.out > /dev/null + ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t10.out > /dev/null + ++t11: ++ ${TEST_SSH_SSHKEYGEN} -E sha256 -lf ${.CURDIR}/rsa_openssh.pub |\ ++ awk '{print $$2}' | diff - ${.CURDIR}/t11.ok ++ + t-exec: ${LTESTS:=.sh} + @if [ "x$?" = "x" ]; then exit 0; fi; \ + for TEST in ""$?; do \ +diff --git a/regress/t11.ok b/regress/t11.ok +new file mode 100644 +index 0000000..1925bb4 +--- /dev/null ++++ b/regress/t11.ok +@@ -0,0 +1 @@ ++SHA256:4w1rnrek3klTJOTVhwuCIFd5k+pq9Bfo5KTxxb8BqbY +diff --git a/regress/t4.ok b/regress/t4.ok +index 8c4942b..4631ea8 100644 +--- a/regress/t4.ok ++++ b/regress/t4.ok +@@ -1 +1 @@ +-3b:dd:44:e9:49:18:84:95:f1:e7:33:6b:9d:93:b1:36 ++MD5:3b:dd:44:e9:49:18:84:95:f1:e7:33:6b:9d:93:b1:36 +diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c +index 764f7fb..9c38a7c 100644 +--- a/regress/unittests/sshkey/test_file.c ++++ b/regress/unittests/sshkey/test_file.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: test_file.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */ ++/* $OpenBSD: test_file.c,v 1.2 2014/12/22 02:15:52 djm Exp $ */ + /* + * Regress test for sshkey.h key management API + * +@@ -33,6 +33,7 @@ + #include "authfile.h" + #include "sshkey.h" + #include "sshbuf.h" ++#include "digest.h" + + #include "common.h" + +@@ -81,7 +82,7 @@ sshkey_file_tests(void) + + TEST_START("RSA1 key hex fingerprint"); + buf = load_text_file("rsa1_1.fp"); +- cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -90,7 +91,7 @@ sshkey_file_tests(void) + + TEST_START("RSA1 key bubblebabble fingerprint"); + buf = load_text_file("rsa1_1.fp.bb"); +- cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -164,7 +165,7 @@ sshkey_file_tests(void) + + TEST_START("RSA key hex fingerprint"); + buf = load_text_file("rsa_1.fp"); +- cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -173,7 +174,7 @@ sshkey_file_tests(void) + + TEST_START("RSA cert hex fingerprint"); + buf = load_text_file("rsa_1-cert.fp"); +- cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k2, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -183,7 +184,7 @@ sshkey_file_tests(void) + + TEST_START("RSA key bubblebabble fingerprint"); + buf = load_text_file("rsa_1.fp.bb"); +- cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -257,7 +258,7 @@ sshkey_file_tests(void) + + TEST_START("DSA key hex fingerprint"); + buf = load_text_file("dsa_1.fp"); +- cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -266,7 +267,7 @@ sshkey_file_tests(void) + + TEST_START("DSA cert hex fingerprint"); + buf = load_text_file("dsa_1-cert.fp"); +- cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k2, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -276,7 +277,7 @@ sshkey_file_tests(void) + + TEST_START("DSA key bubblebabble fingerprint"); + buf = load_text_file("dsa_1.fp.bb"); +- cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -357,7 +358,7 @@ sshkey_file_tests(void) + + TEST_START("ECDSA key hex fingerprint"); + buf = load_text_file("ecdsa_1.fp"); +- cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -366,7 +367,7 @@ sshkey_file_tests(void) + + TEST_START("ECDSA cert hex fingerprint"); + buf = load_text_file("ecdsa_1-cert.fp"); +- cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k2, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -376,7 +377,7 @@ sshkey_file_tests(void) + + TEST_START("ECDSA key bubblebabble fingerprint"); + buf = load_text_file("ecdsa_1.fp.bb"); +- cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -424,7 +425,7 @@ sshkey_file_tests(void) + + TEST_START("Ed25519 key hex fingerprint"); + buf = load_text_file("ed25519_1.fp"); +- cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -433,7 +434,7 @@ sshkey_file_tests(void) + + TEST_START("Ed25519 cert hex fingerprint"); + buf = load_text_file("ed25519_1-cert.fp"); +- cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX); ++ cp = sshkey_fingerprint(k2, SSH_DIGEST_MD5, SSH_FP_HEX); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +@@ -443,7 +444,7 @@ sshkey_file_tests(void) + + TEST_START("Ed25519 key bubblebabble fingerprint"); + buf = load_text_file("ed25519_1.fp.bb"); +- cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE); ++ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); + ASSERT_PTR_NE(cp, NULL); + ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); + sshbuf_free(buf); +diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.fp b/regress/unittests/sshkey/testdata/dsa_1-cert.fp +index 56ee1f8..b26145b 100644 +--- a/regress/unittests/sshkey/testdata/dsa_1-cert.fp ++++ b/regress/unittests/sshkey/testdata/dsa_1-cert.fp +@@ -1 +1 @@ +-5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74 ++MD5:5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74 +diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp b/regress/unittests/sshkey/testdata/dsa_1.fp +index 56ee1f8..b26145b 100644 +--- a/regress/unittests/sshkey/testdata/dsa_1.fp ++++ b/regress/unittests/sshkey/testdata/dsa_1.fp +@@ -1 +1 @@ +-5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74 ++MD5:5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74 +diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp b/regress/unittests/sshkey/testdata/dsa_2.fp +index ba9de82..8226574 100644 +--- a/regress/unittests/sshkey/testdata/dsa_2.fp ++++ b/regress/unittests/sshkey/testdata/dsa_2.fp +@@ -1 +1 @@ +-72:5f:50:6b:e5:64:c5:62:21:92:3f:8b:10:9b:9f:1a ++MD5:72:5f:50:6b:e5:64:c5:62:21:92:3f:8b:10:9b:9f:1a +diff --git a/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp +index a56dbc8..c3d747a 100644 +--- a/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp ++++ b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp +@@ -1 +1 @@ +-f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44 ++MD5:f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44 +diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.fp b/regress/unittests/sshkey/testdata/ecdsa_1.fp +index a56dbc8..c3d747a 100644 +--- a/regress/unittests/sshkey/testdata/ecdsa_1.fp ++++ b/regress/unittests/sshkey/testdata/ecdsa_1.fp +@@ -1 +1 @@ +-f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44 ++MD5:f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44 +diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.fp b/regress/unittests/sshkey/testdata/ecdsa_2.fp +index eb4bbdf..fe7526b 100644 +--- a/regress/unittests/sshkey/testdata/ecdsa_2.fp ++++ b/regress/unittests/sshkey/testdata/ecdsa_2.fp +@@ -1 +1 @@ +-51:bd:ff:2b:6d:26:9b:90:f9:e1:4a:ca:a0:29:8e:70 ++MD5:51:bd:ff:2b:6d:26:9b:90:f9:e1:4a:ca:a0:29:8e:70 +diff --git a/regress/unittests/sshkey/testdata/ed25519_1-cert.fp b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp +index e6d23d0..fbde87a 100644 +--- a/regress/unittests/sshkey/testdata/ed25519_1-cert.fp ++++ b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp +@@ -1 +1 @@ +-19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f ++MD5:19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f +diff --git a/regress/unittests/sshkey/testdata/ed25519_1.fp b/regress/unittests/sshkey/testdata/ed25519_1.fp +index e6d23d0..fbde87a 100644 +--- a/regress/unittests/sshkey/testdata/ed25519_1.fp ++++ b/regress/unittests/sshkey/testdata/ed25519_1.fp +@@ -1 +1 @@ +-19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f ++MD5:19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f +diff --git a/regress/unittests/sshkey/testdata/ed25519_2.fp b/regress/unittests/sshkey/testdata/ed25519_2.fp +index 02c684f..ec1cdbb 100644 +--- a/regress/unittests/sshkey/testdata/ed25519_2.fp ++++ b/regress/unittests/sshkey/testdata/ed25519_2.fp +@@ -1 +1 @@ +-5c:c9:ae:a3:0c:aa:28:29:b8:fc:7c:64:ba:6e:e9:c9 ++MD5:5c:c9:ae:a3:0c:aa:28:29:b8:fc:7c:64:ba:6e:e9:c9 +diff --git a/regress/unittests/sshkey/testdata/rsa1_1.fp b/regress/unittests/sshkey/testdata/rsa1_1.fp +index 782ece0..2e1068c 100644 +--- a/regress/unittests/sshkey/testdata/rsa1_1.fp ++++ b/regress/unittests/sshkey/testdata/rsa1_1.fp +@@ -1 +1 @@ +-a8:82:9b:98:c5:e6:19:d6:83:39:9f:4d:3a:8f:7c:80 ++MD5:a8:82:9b:98:c5:e6:19:d6:83:39:9f:4d:3a:8f:7c:80 +diff --git a/regress/unittests/sshkey/testdata/rsa1_2.fp b/regress/unittests/sshkey/testdata/rsa1_2.fp +index c332537..cd00393 100644 +--- a/regress/unittests/sshkey/testdata/rsa1_2.fp ++++ b/regress/unittests/sshkey/testdata/rsa1_2.fp +@@ -1 +1 @@ +-c0:83:1c:97:5f:32:77:7e:e4:e3:e9:29:b9:eb:76:9c ++MD5:c0:83:1c:97:5f:32:77:7e:e4:e3:e9:29:b9:eb:76:9c +diff --git a/regress/unittests/sshkey/testdata/rsa_1-cert.fp b/regress/unittests/sshkey/testdata/rsa_1-cert.fp +index bf9c2e3..1cf780d 100644 +--- a/regress/unittests/sshkey/testdata/rsa_1-cert.fp ++++ b/regress/unittests/sshkey/testdata/rsa_1-cert.fp +@@ -1 +1 @@ +-be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b ++MD5:be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b +diff --git a/regress/unittests/sshkey/testdata/rsa_1.fp b/regress/unittests/sshkey/testdata/rsa_1.fp +index bf9c2e3..1cf780d 100644 +--- a/regress/unittests/sshkey/testdata/rsa_1.fp ++++ b/regress/unittests/sshkey/testdata/rsa_1.fp +@@ -1 +1 @@ +-be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b ++MD5:be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b +diff --git a/regress/unittests/sshkey/testdata/rsa_2.fp b/regress/unittests/sshkey/testdata/rsa_2.fp +index 53939f4..8d43676 100644 +--- a/regress/unittests/sshkey/testdata/rsa_2.fp ++++ b/regress/unittests/sshkey/testdata/rsa_2.fp +@@ -1 +1 @@ +-fb:8f:7b:26:3d:42:40:ef:ed:f1:ed:ee:66:9e:ba:b0 ++MD5:fb:8f:7b:26:3d:42:40:ef:ed:f1:ed:ee:66:9e:ba:b0 +diff --git a/servconf.c b/servconf.c +index b7f3294..e3ebaac 100644 +--- a/servconf.c ++++ b/servconf.c @@ -54,6 +54,7 @@ #include "packet.h" #include "hostfile.h" @@ -408,7 +701,7 @@ diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c static void add_listen_addr(ServerOptions *, char *, int); static void add_one_listen_addr(ServerOptions *, char *, int); -@@ -157,6 +158,7 @@ initialize_server_options(ServerOptions +@@ -157,6 +158,7 @@ initialize_server_options(ServerOptions *options) options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->version_addendum = NULL; @@ -416,7 +709,7 @@ diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c } void -@@ -312,6 +314,8 @@ fill_default_server_options(ServerOption +@@ -312,6 +314,8 @@ fill_default_server_options(ServerOptions *options) options->fwd_opts.streamlocal_bind_mask = 0177; if (options->fwd_opts.streamlocal_bind_unlink == -1) options->fwd_opts.streamlocal_bind_unlink = 0; @@ -442,7 +735,7 @@ diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c { NULL, sBadOption, 0 } }; -@@ -1663,6 +1668,18 @@ process_server_config_line(ServerOptions +@@ -1663,6 +1668,18 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->fwd_opts.streamlocal_bind_unlink; goto parse_flag; @@ -478,9 +771,10 @@ diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c /* string arguments */ dump_cfg_string(sPidFile, o->pid_file); -diff -up openssh-6.7p1/servconf.h.fingerprint openssh-6.7p1/servconf.h ---- openssh-6.7p1/servconf.h.fingerprint 2014-07-18 06:11:26.000000000 +0200 -+++ openssh-6.7p1/servconf.h 2014-12-22 13:10:57.964878102 +0100 +diff --git a/servconf.h b/servconf.h +index 766db3a..49b228b 100644 +--- a/servconf.h ++++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.114 2014/07/15 15:54:14 millert Exp $ */ +/* $OpenBSD: servconf.h,v 1.115 2014/12/21 22:27:56 djm Exp $ */ @@ -496,21 +790,10 @@ diff -up openssh-6.7p1/servconf.h.fingerprint openssh-6.7p1/servconf.h } ServerOptions; /* Information about the incoming connection as used by Match */ -diff -up openssh-6.7p1/ssh.1.fingerprint openssh-6.7p1/ssh.1 ---- openssh-6.7p1/ssh.1.fingerprint 2014-07-30 04:32:28.000000000 +0200 -+++ openssh-6.7p1/ssh.1 2014-12-22 13:10:57.967878092 +0100 -@@ -1083,7 +1083,7 @@ Fingerprints can be determined using - If the fingerprint is already known, it can be matched - and the key can be accepted or rejected. - Because of the difficulty of comparing host keys --just by looking at hex strings, -+just by looking at fingerprint strings, - there is also support to compare host keys visually, - using - .Em random art . -diff -up openssh-6.7p1/ssh-add.1.fingerprint openssh-6.7p1/ssh-add.1 ---- openssh-6.7p1/ssh-add.1.fingerprint 2013-12-18 07:46:28.000000000 +0100 -+++ openssh-6.7p1/ssh-add.1 2014-12-22 13:10:57.964878102 +0100 +diff --git a/ssh-add.1 b/ssh-add.1 +index 4812448..04d1840 100644 +--- a/ssh-add.1 ++++ b/ssh-add.1 @@ -44,6 +44,7 @@ .Sh SYNOPSIS .Nm ssh-add @@ -519,7 +802,7 @@ diff -up openssh-6.7p1/ssh-add.1.fingerprint openssh-6.7p1/ssh-add.1 .Op Fl t Ar life .Op Ar .Nm ssh-add -@@ -108,6 +109,14 @@ If no public key is found at a given pat +@@ -108,6 +109,14 @@ If no public key is found at a given path, will append .Pa .pub and retry. @@ -534,9 +817,10 @@ diff -up openssh-6.7p1/ssh-add.1.fingerprint openssh-6.7p1/ssh-add.1 .It Fl e Ar pkcs11 Remove keys provided by the PKCS#11 shared library .Ar pkcs11 . -diff -up openssh-6.7p1/ssh-add.c.fingerprint openssh-6.7p1/ssh-add.c ---- openssh-6.7p1/ssh-add.c.fingerprint 2014-07-11 01:19:05.000000000 +0200 -+++ openssh-6.7p1/ssh-add.c 2014-12-22 13:10:57.965878099 +0100 +diff --git a/ssh-add.c b/ssh-add.c +index 78a3359..5d6a5f4 100644 +--- a/ssh-add.c ++++ b/ssh-add.c @@ -63,6 +63,7 @@ #include "pathnames.h" #include "misc.h" @@ -554,7 +838,7 @@ diff -up openssh-6.7p1/ssh-add.c.fingerprint openssh-6.7p1/ssh-add.c /* Default lifetime (0 == forever) */ static int lifetime = 0; -@@ -340,8 +343,8 @@ list_identities(AuthenticationConnection +@@ -340,8 +343,8 @@ list_identities(AuthenticationConnection *ac, int do_fp) key = ssh_get_next_identity(ac, &comment, version)) { had_identities = 1; if (do_fp) { @@ -653,9 +937,10 @@ diff -up openssh-6.7p1/ssh-add.c.fingerprint openssh-6.7p1/ssh-add.c argc -= optind; argv += optind; if (pkcs11provider != NULL) { -diff -up openssh-6.7p1/ssh-agent.1.fingerprint openssh-6.7p1/ssh-agent.1 ---- openssh-6.7p1/ssh-agent.1.fingerprint 2014-04-20 05:25:09.000000000 +0200 -+++ openssh-6.7p1/ssh-agent.1 2014-12-22 13:10:57.965878099 +0100 +diff --git a/ssh-agent.1 b/ssh-agent.1 +index a1e634f..d7e791b 100644 +--- a/ssh-agent.1 ++++ b/ssh-agent.1 @@ -45,6 +45,7 @@ .Op Fl c | s .Op Fl d @@ -679,9 +964,10 @@ diff -up openssh-6.7p1/ssh-agent.1.fingerprint openssh-6.7p1/ssh-agent.1 .It Fl k Kill the current agent (given by the .Ev SSH_AGENT_PID -diff -up openssh-6.7p1/ssh-agent.c.fingerprint openssh-6.7p1/ssh-agent.c ---- openssh-6.7p1/ssh-agent.c.fingerprint 2014-07-30 04:32:46.000000000 +0200 -+++ openssh-6.7p1/ssh-agent.c 2014-12-22 13:10:57.965878099 +0100 +diff --git a/ssh-agent.c b/ssh-agent.c +index 25f10c5..c8036c8 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c @@ -142,6 +142,8 @@ extern char *__progname; /* Default lifetime in seconds (0 == forever) */ static long lifetime = 0; @@ -724,141 +1010,359 @@ diff -up openssh-6.7p1/ssh-agent.c.fingerprint openssh-6.7p1/ssh-agent.c case 'c': if (s_flag) usage(); -diff -up openssh-6.7p1/sshconnect2.c.fingerprint openssh-6.7p1/sshconnect2.c ---- openssh-6.7p1/sshconnect2.c.fingerprint 2014-07-18 06:11:27.000000000 +0200 -+++ openssh-6.7p1/sshconnect2.c 2014-12-22 13:10:57.968878088 +0100 -@@ -582,7 +582,7 @@ input_userauth_pk_ok(int type, u_int32_t - key->type, pktype); - goto done; - } -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); - debug2("input_userauth_pk_ok: fp %s", fp); - free(fp); - -@@ -991,7 +991,7 @@ sign_and_send_pubkey(Authctxt *authctxt, - int have_sig = 1; - char *fp; - -- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(id->key, options.fingerprint_hash, SSH_FP_DEFAULT); - debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); - free(fp); - -diff -up openssh-6.7p1/sshconnect.c.fingerprint openssh-6.7p1/sshconnect.c ---- openssh-6.7p1/sshconnect.c.fingerprint 2014-07-18 06:11:26.000000000 +0200 -+++ openssh-6.7p1/sshconnect.c 2014-12-22 13:15:28.371939131 +0100 -@@ -915,9 +915,10 @@ check_host_key(char *hostname, struct so - "key for IP address '%.128s' to the list " - "of known hosts.", type, ip); - } else if (options.visual_host_key) { -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(host_key, SSH_FP_MD5, -- SSH_FP_RANDOMART); -+ fp = key_fingerprint(host_key, -+ options.fingerprint_hash, SSH_FP_DEFAULT); -+ ra = key_fingerprint(host_key, -+ options.fingerprint_hash, SSH_FP_RANDOMART); - logit("Host key fingerprint is %s\n%s\n", fp, ra); - free(ra); - free(fp); -@@ -956,9 +957,10 @@ 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, -- SSH_FP_RANDOMART); -+ fp = key_fingerprint(host_key, -+ options.fingerprint_hash, SSH_FP_DEFAULT); -+ ra = key_fingerprint(host_key, -+ options.fingerprint_hash, SSH_FP_RANDOMART); - msg2[0] = '\0'; - if (options.verify_host_key_dns) { - if (matching_host_key_dns) -@@ -1222,7 +1224,7 @@ verify_host_key(char *host, struct socka - char *fp; - Key *plain = NULL; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT); - debug("Server host key: %s %s", key_type(host_key), fp); - free(fp); - -@@ -1356,8 +1358,10 @@ show_other_keys(struct hostkeys *hostkey - continue; - if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) - continue; -- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); -+ fp = key_fingerprint(found->key, -+ options.fingerprint_hash, SSH_FP_DEFAULT); -+ ra = key_fingerprint(found->key, -+ options.fingerprint_hash, SSH_FP_RANDOMART); - logit("WARNING: %s key found for host %s\n" - "in %s:%lu\n" - "%s key fingerprint %s.", -@@ -1378,7 +1382,8 @@ warn_changed_key(Key *host_key) - { - char *fp; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(host_key, options.fingerprint_hash, -+ SSH_FP_DEFAULT); - - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); -diff -up openssh-6.7p1/sshd_config.5.fingerprint openssh-6.7p1/sshd_config.5 ---- openssh-6.7p1/sshd_config.5.fingerprint 2014-10-03 01:24:57.000000000 +0200 -+++ openssh-6.7p1/sshd_config.5 2014-12-22 13:10:57.968878088 +0100 -@@ -483,6 +483,15 @@ and finally - See PATTERNS in - .Xr ssh_config 5 - for more information on patterns. -+.It Cm FingerprintHash -+Specifies the hash algorithm used when logging key fingerprints. +diff --git a/ssh-keygen.1 b/ssh-keygen.1 +index 723a016..276dacc 100644 +--- a/ssh-keygen.1 ++++ b/ssh-keygen.1 +@@ -73,6 +73,7 @@ + .Op Fl f Ar keyfile + .Nm ssh-keygen + .Fl l ++.Op Fl E Ar fingerprint_hash + .Op Fl f Ar input_keyfile + .Nm ssh-keygen + .Fl B +@@ -269,6 +270,14 @@ When used in combination with + this option indicates that a CA key resides in a PKCS#11 token (see the + .Sx CERTIFICATES + section for details). ++.It Fl E Ar fingerprint_hash ++Specifies the hash algorithm used when displaying key fingerprints. +Valid options are: +.Dq md5 +and +.Dq sha256 . +The default is +.Dq sha256 . -+.Pp - .It Cm ForceCommand - Forces the execution of the command specified by - .Cm ForceCommand , -diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c ---- openssh-6.7p1/sshkey.c.fingerprint 2014-07-21 17:07:11.000000000 +0200 -+++ openssh-6.7p1/sshkey.c 2014-12-22 13:10:57.969878085 +0100 -@@ -29,6 +29,7 @@ + .It Fl e + This option will read a private or public OpenSSH key file and + print to stdout the key in one of the formats specified by the +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 23058ee..64fa217 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -53,6 +53,7 @@ + #include "ssh-pkcs11.h" + #include "atomicio.h" + #include "krl.h" ++#include "digest.h" - #include - #include -+#include + /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ + #define DEFAULT_BITS 2048 +@@ -90,6 +91,9 @@ int show_cert = 0; + int print_fingerprint = 0; + int print_bubblebabble = 0; - #include - #include -@@ -852,29 +853,18 @@ sshkey_plain_to_blob(const struct sshkey - } ++/* Hash algorithm to use for fingerprints. */ ++int fingerprint_hash = SSH_FP_HASH_DEFAULT; ++ + /* The identity file name, given on the command line or entered by the user. */ + char identity_file[1024]; + int have_identity = 0; +@@ -749,11 +753,11 @@ do_download(struct passwd *pw) + Key **keys = NULL; + int i, nkeys; + enum fp_rep rep; +- enum fp_type fptype; ++ int fptype; + char *fp, *ra; - int --sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, -+sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, - u_char **retp, size_t *lenp) - { - u_char *blob = NULL, *ret = NULL; - size_t blob_len = 0; -- int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR; -+ int r = SSH_ERR_INTERNAL_ERROR; +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; +- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; ++ fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; ++ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; - if (retp != NULL) - *retp = NULL; - if (lenp != NULL) - *lenp = 0; -- -- switch (dgst_type) { -- case SSH_FP_MD5: -- hash_alg = SSH_DIGEST_MD5; + pkcs11_init(0); + nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); +@@ -762,7 +766,7 @@ do_download(struct passwd *pw) + for (i = 0; i < nkeys; i++) { + if (print_fingerprint) { + fp = key_fingerprint(keys[i], fptype, rep); +- ra = key_fingerprint(keys[i], SSH_FP_MD5, ++ ra = key_fingerprint(keys[i], fingerprint_hash, + SSH_FP_RANDOMART); + printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), + fp, key_type(keys[i])); +@@ -792,12 +796,11 @@ do_fingerprint(struct passwd *pw) + char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; + int i, skip = 0, num = 0, invalid = 1; + enum fp_rep rep; +- enum fp_type fptype; ++ int fptype; + struct stat st; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; +- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; +- ++ fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; ++ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { +@@ -807,7 +810,8 @@ do_fingerprint(struct passwd *pw) + public = key_load_public(identity_file, &comment); + if (public != NULL) { + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, fingerprint_hash, ++ SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, comment, + key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) +@@ -873,7 +877,8 @@ do_fingerprint(struct passwd *pw) + } + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, fingerprint_hash, ++ SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, + comment ? comment : "no comment", key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) +@@ -991,13 +996,15 @@ printhost(FILE *f, const char *name, Key *public, int ca, int revoked, int hash) + { + if (print_fingerprint) { + enum fp_rep rep; +- enum fp_type fptype; ++ int fptype; + char *fp, *ra; + +- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; +- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; ++ fptype = print_bubblebabble ? ++ SSH_DIGEST_SHA1 : fingerprint_hash; ++ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; + fp = key_fingerprint(public, fptype, rep); +- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); ++ ra = key_fingerprint(public, fingerprint_hash, ++ SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, name, + key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) +@@ -1906,9 +1913,9 @@ do_show_cert(struct passwd *pw) + fatal("%s is not a certificate", identity_file); + v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; + +- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ key_fp = key_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); + ca_fp = key_fingerprint(key->cert->signature_key, +- SSH_FP_MD5, SSH_FP_HEX); ++ fingerprint_hash, SSH_FP_DEFAULT); + + printf("%s:\n", identity_file); + printf(" Type: %s %s certificate\n", key_ssh_name(key), +@@ -2187,7 +2194,7 @@ usage(void) + " ssh-keygen -e [-m key_format] [-f input_keyfile]\n" + " ssh-keygen -y [-f input_keyfile]\n" + " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" +- " ssh-keygen -l [-f input_keyfile]\n" ++ " ssh-keygen -l [-E fingerprint_hash] [-f input_keyfile]\n" + " ssh-keygen -B [-f input_keyfile]\n"); + #ifdef ENABLE_PKCS11 + fprintf(stderr, +@@ -2256,9 +2263,10 @@ main(int argc, char **argv) + exit(1); + } + +- /* Remaining characters: EUYdw */ ++ /* Remaining characters: UYdw */ + while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" +- "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { ++ "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" ++ "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { + switch (opt) { + case 'A': + gen_all_hostkeys = 1; +@@ -2269,6 +2277,11 @@ main(int argc, char **argv) + fatal("Bits has bad value %s (%s)", + optarg, errstr); + break; ++ case 'E': ++ fingerprint_hash = ssh_digest_alg_by_name(optarg); ++ if (fingerprint_hash == -1) ++ fatal("Invalid hash algorithm \"%s\"", optarg); ++ break; + case 'F': + find_host = 1; + rr_hostname = optarg; +@@ -2700,8 +2713,9 @@ 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, ++ char *fp = key_fingerprint(public, fingerprint_hash, ++ SSH_FP_DEFAULT); ++ char *ra = key_fingerprint(public, fingerprint_hash, + SSH_FP_RANDOMART); + printf("Your public key has been saved in %s.\n", + identity_file); +diff --git a/ssh-keysign.c b/ssh-keysign.c +index d95bb7d..3526d7d 100644 +--- a/ssh-keysign.c ++++ b/ssh-keysign.c +@@ -246,7 +246,8 @@ main(int argc, char **argv) + } + } + if (!found) { +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, options.fingerprint_hash, ++ SSH_FP_DEFAULT); + fatal("no matching hostkey found for key %s %s", + key_type(key), fp); + } +diff --git a/ssh.1 b/ssh.1 +index fa5cfb2..d3198a1 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -1083,7 +1083,7 @@ Fingerprints can be determined using + If the fingerprint is already known, it can be matched + and the key can be accepted or rejected. + Because of the difficulty of comparing host keys +-just by looking at hex strings, ++just by looking at fingerprint strings, + there is also support to compare host keys visually, + using + .Em random art . +diff --git a/sshconnect.c b/sshconnect.c +index ac09eae..7db31e6 100644 +--- a/sshconnect.c ++++ b/sshconnect.c +@@ -915,9 +915,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, + "key for IP address '%.128s' to the list " + "of known hosts.", type, ip); + } else if (options.visual_host_key) { +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(host_key, SSH_FP_MD5, +- SSH_FP_RANDOMART); ++ fp = key_fingerprint(host_key, ++ options.fingerprint_hash, SSH_FP_DEFAULT); ++ ra = key_fingerprint(host_key, ++ options.fingerprint_hash, SSH_FP_RANDOMART); + logit("Host key fingerprint is %s\n%s\n", fp, ra); + free(ra); + free(fp); +@@ -956,9 +957,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, + 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, +- SSH_FP_RANDOMART); ++ fp = key_fingerprint(host_key, ++ options.fingerprint_hash, SSH_FP_DEFAULT); ++ ra = key_fingerprint(host_key, ++ options.fingerprint_hash, SSH_FP_RANDOMART); + msg2[0] = '\0'; + if (options.verify_host_key_dns) { + if (matching_host_key_dns) +@@ -1222,7 +1224,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) + char *fp; + Key *plain = NULL; + +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT); + debug("Server host key: %s %s", key_type(host_key), fp); + free(fp); + +@@ -1356,8 +1358,10 @@ show_other_keys(struct hostkeys *hostkeys, Key *key) + continue; + if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) + continue; +- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); +- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); ++ fp = key_fingerprint(found->key, ++ options.fingerprint_hash, SSH_FP_DEFAULT); ++ ra = key_fingerprint(found->key, ++ options.fingerprint_hash, SSH_FP_RANDOMART); + logit("WARNING: %s key found for host %s\n" + "in %s:%lu\n" + "%s key fingerprint %s.", +@@ -1378,7 +1382,8 @@ warn_changed_key(Key *host_key) + { + char *fp; + +- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(host_key, options.fingerprint_hash, ++ SSH_FP_DEFAULT); + + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); +diff --git a/sshconnect2.c b/sshconnect2.c +index 68f7f4f..4724b66 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -582,7 +582,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) + key->type, pktype); + goto done; + } +- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); + debug2("input_userauth_pk_ok: fp %s", fp); + free(fp); + +@@ -991,7 +991,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) + int have_sig = 1; + char *fp; + +- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(id->key, options.fingerprint_hash, SSH_FP_DEFAULT); + debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); + free(fp); + +diff --git a/sshd_config.5 b/sshd_config.5 +index fd44abe..0449eeb 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -483,6 +483,15 @@ and finally + See PATTERNS in + .Xr ssh_config 5 + for more information on patterns. ++.It Cm FingerprintHash ++Specifies the hash algorithm used when logging key fingerprints. ++Valid options are: ++.Dq md5 ++and ++.Dq sha256 . ++The default is ++.Dq sha256 . ++.Pp + .It Cm ForceCommand + Forces the execution of the command specified by + .Cm ForceCommand , +diff --git a/sshkey.c b/sshkey.c +index fdd0c8a..70df758 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -29,6 +29,7 @@ + + #include + #include ++#include + + #include + #include +@@ -852,29 +853,18 @@ sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) + } + + int +-sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, ++sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, + u_char **retp, size_t *lenp) + { + u_char *blob = NULL, *ret = NULL; + size_t blob_len = 0; +- int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR; ++ int r = SSH_ERR_INTERNAL_ERROR; + + if (retp != NULL) + *retp = NULL; + if (lenp != NULL) + *lenp = 0; +- +- switch (dgst_type) { +- case SSH_FP_MD5: +- hash_alg = SSH_DIGEST_MD5; - break; - case SSH_FP_SHA1: - hash_alg = SSH_DIGEST_SHA1; @@ -871,7 +1375,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c r = SSH_ERR_INVALID_ARGUMENT; goto out; } -@@ -899,7 +889,7 @@ sshkey_fingerprint_raw(const struct sshk +@@ -899,7 +889,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, r = SSH_ERR_ALLOC_FAIL; goto out; } @@ -880,7 +1384,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c ret, SSH_DIGEST_MAX_LENGTH)) != 0) goto out; /* success */ -@@ -908,7 +898,7 @@ sshkey_fingerprint_raw(const struct sshk +@@ -908,7 +898,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, ret = NULL; } if (lenp != NULL) @@ -889,7 +1393,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c r = 0; out: free(ret); -@@ -920,21 +910,45 @@ sshkey_fingerprint_raw(const struct sshk +@@ -920,21 +910,45 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, } static char * @@ -924,15 +1428,15 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c + ret[strcspn(ret, "=")] = '\0'; + return ret; +} -+ + +- /* Remove the trailing ':' character */ +- retval[(dgst_raw_len * 3) - 1] = '\0'; +static char * +fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) +{ + char *retval, hex[5]; + size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2; - -- /* Remove the trailing ':' character */ -- retval[(dgst_raw_len * 3) - 1] = '\0'; ++ + if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL) + return NULL; + strlcpy(retval, alg, rlen); @@ -945,7 +1449,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c return retval; } -@@ -1020,7 +1034,7 @@ fingerprint_bubblebabble(u_char *dgst_ra +@@ -1020,7 +1034,7 @@ fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len) #define FLDSIZE_Y (FLDBASE + 1) #define FLDSIZE_X (FLDBASE * 2 + 1) static char * @@ -954,7 +1458,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c const struct sshkey *k) { /* -@@ -1028,9 +1042,9 @@ fingerprint_randomart(u_char *dgst_raw, +@@ -1028,9 +1042,9 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, * intersects with itself. Matter of taste. */ char *augmentation_string = " .o+=*BOX@%&#/^SE"; @@ -966,7 +1470,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c u_int b; int x, y, r; size_t len = strlen(augmentation_string) - 1; -@@ -1075,8 +1089,12 @@ fingerprint_randomart(u_char *dgst_raw, +@@ -1075,8 +1089,12 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, sshkey_type(k), sshkey_size(k)); /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ if (r < 0 || r > (int)sizeof(title)) @@ -981,7 +1485,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c /* output upper border */ p = retval; -@@ -1085,7 +1103,7 @@ fingerprint_randomart(u_char *dgst_raw, +@@ -1085,7 +1103,7 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, *p++ = '-'; memcpy(p, title, tlen); p += tlen; @@ -990,7 +1494,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c *p++ = '-'; *p++ = '+'; *p++ = '\n'; -@@ -1101,7 +1119,11 @@ fingerprint_randomart(u_char *dgst_raw, +@@ -1101,7 +1119,11 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, /* output lower border */ *p++ = '+'; @@ -1003,7 +1507,7 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c *p++ = '-'; *p++ = '+'; -@@ -1109,24 +1131,39 @@ fingerprint_randomart(u_char *dgst_raw, +@@ -1109,24 +1131,39 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, } char * @@ -1047,194 +1551,10 @@ diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c break; default: explicit_bzero(dgst_raw, dgst_raw_len); -diff -up openssh-6.7p1/ssh-keygen.1.fingerprint openssh-6.7p1/ssh-keygen.1 ---- openssh-6.7p1/ssh-keygen.1.fingerprint 2014-04-20 05:23:04.000000000 +0200 -+++ openssh-6.7p1/ssh-keygen.1 2014-12-22 13:10:57.966878095 +0100 -@@ -73,6 +73,7 @@ - .Op Fl f Ar keyfile - .Nm ssh-keygen - .Fl l -+.Op Fl E Ar fingerprint_hash - .Op Fl f Ar input_keyfile - .Nm ssh-keygen - .Fl B -@@ -269,6 +270,14 @@ When used in combination with - this option indicates that a CA key resides in a PKCS#11 token (see the - .Sx CERTIFICATES - section for details). -+.It Fl E Ar fingerprint_hash -+Specifies the hash algorithm used when displaying key fingerprints. -+Valid options are: -+.Dq md5 -+and -+.Dq sha256 . -+The default is -+.Dq sha256 . - .It Fl e - This option will read a private or public OpenSSH key file and - print to stdout the key in one of the formats specified by the -diff -up openssh-6.7p1/ssh-keygen.c.fingerprint openssh-6.7p1/ssh-keygen.c ---- openssh-6.7p1/ssh-keygen.c.fingerprint 2014-07-03 13:24:41.000000000 +0200 -+++ openssh-6.7p1/ssh-keygen.c 2014-12-22 13:10:57.966878095 +0100 -@@ -53,6 +53,7 @@ - #include "ssh-pkcs11.h" - #include "atomicio.h" - #include "krl.h" -+#include "digest.h" - - /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ - #define DEFAULT_BITS 2048 -@@ -90,6 +91,9 @@ int show_cert = 0; - int print_fingerprint = 0; - int print_bubblebabble = 0; - -+/* Hash algorithm to use for fingerprints. */ -+int fingerprint_hash = SSH_FP_HASH_DEFAULT; -+ - /* The identity file name, given on the command line or entered by the user. */ - char identity_file[1024]; - int have_identity = 0; -@@ -749,11 +753,11 @@ do_download(struct passwd *pw) - Key **keys = NULL; - int i, nkeys; - enum fp_rep rep; -- enum fp_type fptype; -+ int fptype; - char *fp, *ra; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; -+ fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; -+ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; - - pkcs11_init(0); - nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); -@@ -762,7 +766,7 @@ do_download(struct passwd *pw) - for (i = 0; i < nkeys; i++) { - if (print_fingerprint) { - fp = key_fingerprint(keys[i], fptype, rep); -- ra = key_fingerprint(keys[i], SSH_FP_MD5, -+ ra = key_fingerprint(keys[i], fingerprint_hash, - SSH_FP_RANDOMART); - printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), - fp, key_type(keys[i])); -@@ -792,12 +796,11 @@ do_fingerprint(struct passwd *pw) - char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; - int i, skip = 0, num = 0, invalid = 1; - enum fp_rep rep; -- enum fp_type fptype; -+ int fptype; - struct stat st; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; -- -+ fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; -+ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; - if (!have_identity) - ask_filename(pw, "Enter file in which the key is"); - if (stat(identity_file, &st) < 0) { -@@ -807,7 +810,8 @@ do_fingerprint(struct passwd *pw) - public = key_load_public(identity_file, &comment); - if (public != NULL) { - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -+ ra = key_fingerprint(public, fingerprint_hash, -+ SSH_FP_RANDOMART); - printf("%u %s %s (%s)\n", key_size(public), fp, comment, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) -@@ -873,7 +877,8 @@ do_fingerprint(struct passwd *pw) - } - comment = *cp ? cp : comment; - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -+ ra = key_fingerprint(public, fingerprint_hash, -+ SSH_FP_RANDOMART); - printf("%u %s %s (%s)\n", key_size(public), fp, - comment ? comment : "no comment", key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) -@@ -991,13 +996,15 @@ printhost(FILE *f, const char *name, Key - { - if (print_fingerprint) { - enum fp_rep rep; -- enum fp_type fptype; -+ int fptype; - char *fp, *ra; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; -+ fptype = print_bubblebabble ? -+ SSH_DIGEST_SHA1 : fingerprint_hash; -+ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -+ ra = key_fingerprint(public, fingerprint_hash, -+ SSH_FP_RANDOMART); - printf("%u %s %s (%s)\n", key_size(public), fp, name, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) -@@ -1906,9 +1913,9 @@ do_show_cert(struct passwd *pw) - fatal("%s is not a certificate", identity_file); - v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; - -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); - ca_fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ fingerprint_hash, SSH_FP_DEFAULT); - - printf("%s:\n", identity_file); - printf(" Type: %s %s certificate\n", key_ssh_name(key), -@@ -2187,7 +2194,7 @@ usage(void) - " ssh-keygen -e [-m key_format] [-f input_keyfile]\n" - " ssh-keygen -y [-f input_keyfile]\n" - " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" -- " ssh-keygen -l [-f input_keyfile]\n" -+ " ssh-keygen -l [-E fingerprint_hash] [-f input_keyfile]\n" - " ssh-keygen -B [-f input_keyfile]\n"); - #ifdef ENABLE_PKCS11 - fprintf(stderr, -@@ -2256,9 +2263,10 @@ main(int argc, char **argv) - exit(1); - } - -- /* Remaining characters: EUYdw */ -+ /* Remaining characters: UYdw */ - while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" -- "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { -+ "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" -+ "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { - switch (opt) { - case 'A': - gen_all_hostkeys = 1; -@@ -2269,6 +2277,11 @@ main(int argc, char **argv) - fatal("Bits has bad value %s (%s)", - optarg, errstr); - break; -+ case 'E': -+ fingerprint_hash = ssh_digest_alg_by_name(optarg); -+ if (fingerprint_hash == -1) -+ fatal("Invalid hash algorithm \"%s\"", optarg); -+ break; - case 'F': - find_host = 1; - rr_hostname = optarg; -@@ -2700,8 +2713,9 @@ 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, -+ char *fp = key_fingerprint(public, fingerprint_hash, -+ SSH_FP_DEFAULT); -+ char *ra = key_fingerprint(public, fingerprint_hash, - SSH_FP_RANDOMART); - printf("Your public key has been saved in %s.\n", - identity_file); -diff -up openssh-6.7p1/sshkey.h.fingerprint openssh-6.7p1/sshkey.h ---- openssh-6.7p1/sshkey.h.fingerprint 2014-08-20 03:06:51.000000000 +0200 -+++ openssh-6.7p1/sshkey.h 2014-12-22 13:10:57.969878085 +0100 +diff --git a/sshkey.h b/sshkey.h +index 450b30c..4554b09 100644 +--- a/sshkey.h ++++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.1 2014/06/24 01:16:58 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.2 2014/12/21 22:27:55 djm Exp $ */ @@ -1262,7 +1582,7 @@ diff -up openssh-6.7p1/sshkey.h.fingerprint openssh-6.7p1/sshkey.h SSH_FP_BUBBLEBABBLE, SSH_FP_RANDOMART }; -@@ -124,9 +122,9 @@ int sshkey_equal_public(const struct s +@@ -124,9 +122,9 @@ int sshkey_equal_public(const struct sshkey *, const struct sshkey *); int sshkey_equal(const struct sshkey *, const struct sshkey *); char *sshkey_fingerprint(const struct sshkey *, @@ -1274,16 +1594,3 @@ diff -up openssh-6.7p1/sshkey.h.fingerprint openssh-6.7p1/sshkey.h const char *sshkey_type(const struct sshkey *); const char *sshkey_cert_type(const struct sshkey *); int sshkey_write(const struct sshkey *, FILE *); -diff -up openssh-6.7p1/ssh-keysign.c.fingerprint openssh-6.7p1/ssh-keysign.c ---- openssh-6.7p1/ssh-keysign.c.fingerprint 2014-05-15 06:24:10.000000000 +0200 -+++ openssh-6.7p1/ssh-keysign.c 2014-12-22 13:10:57.967878092 +0100 -@@ -246,7 +246,8 @@ main(int argc, char **argv) - } - } - if (!found) { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(key, options.fingerprint_hash, -+ SSH_FP_DEFAULT); - fatal("no matching hostkey found for key %s %s", - key_type(key), fp); - } diff --git a/openssh-6.7p1-fips.patch b/openssh-6.7p1-fips.patch new file mode 100644 index 0000000..ea82670 --- /dev/null +++ b/openssh-6.7p1-fips.patch @@ -0,0 +1,684 @@ +diff --git a/Makefile.in b/Makefile.in +index 9311e16..1eb2b45 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -164,25 +164,25 @@ libssh.a: $(LIBSSH_OBJS) + $(RANLIB) $@ + + ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) +- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) ++ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS) + + sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) +- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) ++ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) + + 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) +@@ -197,7 +197,7 @@ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o + $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -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 --git a/cipher-ctr.c b/cipher-ctr.c +index 73e9c7c..40ee395 100644 +--- a/cipher-ctr.c ++++ b/cipher-ctr.c +@@ -179,7 +179,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 --git a/cipher.c b/cipher.c +index 9cc7cf8..5ebfa84 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -39,6 +39,8 @@ + + #include + ++#include ++ + #include + #include + #include +@@ -99,6 +101,26 @@ static const struct sshcipher ciphers[] = { + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } + }; + ++static const struct sshcipher fips_ciphers[] = { ++ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, ++ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, ++ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, ++ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, ++ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, ++ { "rijndael-cbc@lysator.liu.se", ++ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, ++ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, ++ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, ++ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, ++#ifdef OPENSSL_HAVE_EVPGCM ++ { "aes128-gcm@openssh.com", ++ SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, ++ { "aes256-gcm@openssh.com", ++ SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, ++#endif ++ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } ++}; ++ + /*--*/ + + /* Returns a comma-separated list of supported ciphers. */ +@@ -109,7 +131,7 @@ cipher_alg_list(char sep, int auth_only) + size_t nlen, rlen = 0; + const struct sshcipher *c; + +- for (c = ciphers; c->name != NULL; c++) { ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) { + if (c->number != SSH_CIPHER_SSH2) + continue; + if (auth_only && c->auth_len == 0) +@@ -193,7 +215,7 @@ const struct sshcipher * + cipher_by_name(const char *name) + { + const struct sshcipher *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; +@@ -203,7 +225,7 @@ const struct sshcipher * + cipher_by_number(int id) + { + const struct sshcipher *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; +@@ -244,7 +266,7 @@ cipher_number(const char *name) + const struct sshcipher *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; +diff --git a/dh.h b/dh.h +index 48f7b68..9ff39f4 100644 +--- a/dh.h ++++ b/dh.h +@@ -45,6 +45,7 @@ int dh_estimate(int); + + /* Min and max values from RFC4419. */ + #define DH_GRP_MIN 1024 ++#define DH_GRP_MIN_FIPS 2048 + #define DH_GRP_MAX 8192 + + /* +diff --git a/entropy.c b/entropy.c +index d24e724..06b0095 100644 +--- a/entropy.c ++++ b/entropy.c +@@ -215,6 +215,9 @@ seed_rng(void) + fatal("OpenSSL version mismatch. Built against %lx, you " + "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + ++ /* clean the PRNG status when exiting the program */ ++ atexit(RAND_cleanup); ++ + #ifndef OPENSSL_PRNG_ONLY + if (RAND_status() == 1) { + debug3("RNG is ready, skipping seeding"); +diff --git a/kex.c b/kex.c +index e0cf3de..e11198f 100644 +--- a/kex.c ++++ b/kex.c +@@ -35,6 +35,7 @@ + + #ifdef WITH_OPENSSL + #include ++#include + #endif + + #include "xmalloc.h" +@@ -107,6 +108,25 @@ static const struct kexalg kexalgs[] = { + { NULL, -1, -1, -1}, + }; + ++static const struct kexalg kexalgs_fips[] = { ++ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++#ifdef HAVE_EVP_SHA256 ++ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, ++#endif ++#ifdef OPENSSL_HAS_ECC ++ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, ++ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, ++ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, ++ SSH_DIGEST_SHA384 }, ++# ifdef OPENSSL_HAS_NISTP521 ++ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, ++ SSH_DIGEST_SHA512 }, ++# endif ++#endif ++ { NULL, -1, -1, NULL}, ++}; ++ + char * + kex_alg_list(char sep) + { +@@ -130,7 +150,7 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; + #ifdef GSSAPI +@@ -155,7 +175,10 @@ kex_names_valid(const char *names) + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (kex_alg_by_name(p) == NULL) { +- error("Unsupported KEX algorithm \"%.100s\"", p); ++ if (FIPS_mode()) ++ error("\"%.100s\" is not allowed in FIPS mode", p); ++ else ++ error("Unsupported KEX algorithm \"%.100s\"", p); + free(s); + return 0; + } +diff --git a/kexecdhc.c b/kexecdhc.c +index 2f7629c..20c9946 100644 +--- a/kexecdhc.c ++++ b/kexecdhc.c +@@ -154,6 +154,7 @@ kexecdh_client(Kex *kex) + + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); ++ memset(hash, 0, hashlen); + kex_finish(kex); + } + #else /* OPENSSL_HAS_ECC */ +diff --git a/kexecdhs.c b/kexecdhs.c +index 2700b72..0820894 100644 +--- a/kexecdhs.c ++++ b/kexecdhs.c +@@ -150,6 +150,7 @@ kexecdh_server(Kex *kex) + + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); ++ memset(hash, 0, hashlen); + kex_finish(kex); + } + #else /* OPENSSL_HAS_ECC */ +diff --git a/kexgexc.c b/kexgexc.c +index 0a91bdd..b75930b 100644 +--- a/kexgexc.c ++++ b/kexgexc.c +@@ -26,6 +26,8 @@ + + #include "includes.h" + ++#include ++ + #include + + #include +@@ -58,7 +60,7 @@ kexgex_client(Kex *kex) + int min, max, nbits; + DH *dh; + +- min = DH_GRP_MIN; ++ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + max = DH_GRP_MAX; + + /* Servers with MAX4096DH need a preferred size (nbits) <= 4096. +diff --git a/kexgexs.c b/kexgexs.c +index 770ad28..9d4fc6d 100644 +--- a/kexgexs.c ++++ b/kexgexs.c +@@ -76,16 +76,16 @@ kexgex_server(Kex *kex) + omin = min = packet_get_int(); + onbits = nbits = packet_get_int(); + omax = max = packet_get_int(); +- min = MAX(DH_GRP_MIN, min); ++ min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); +- nbits = MAX(DH_GRP_MIN, nbits); ++ nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); + nbits = MIN(DH_GRP_MAX, nbits); + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); + onbits = nbits = packet_get_int(); + /* unused for old GEX */ +- omin = min = DH_GRP_MIN; ++ omin = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + omax = max = DH_GRP_MAX; + break; + default: +diff --git a/mac.c b/mac.c +index fd07bf2..fedfbb2 100644 +--- a/mac.c ++++ b/mac.c +@@ -27,6 +27,8 @@ + + #include + ++#include ++ + #include + #include + #include +@@ -60,7 +62,7 @@ struct macalg { + int etm; /* Encrypt-then-MAC */ + }; + +-static const struct macalg macs[] = { ++static const struct macalg all_macs[] = { + /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ + { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, + { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, +@@ -91,6 +93,24 @@ static const struct macalg macs[] = { + { NULL, 0, 0, 0, 0, 0, 0 } + }; + ++static const struct macalg fips_macs[] = { ++ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ ++ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, ++#ifdef HAVE_EVP_SHA256 ++ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 }, ++ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, ++#endif ++ ++ /* Encrypt-then-MAC variants */ ++ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, ++#ifdef HAVE_EVP_SHA256 ++ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 }, ++ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 }, ++#endif ++ ++ { NULL, 0, 0, 0, 0, 0, 0 } ++}; ++ + /* Returns a list of supported MACs separated by the specified char. */ + char * + mac_alg_list(char sep) +@@ -99,7 +119,7 @@ mac_alg_list(char sep) + size_t nlen, rlen = 0; + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(m->name); +@@ -133,7 +153,7 @@ mac_setup(Mac *mac, char *name) + { + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { + if (strcmp(name, m->name) != 0) + continue; + if (mac != NULL) { +diff --git a/myproposal.h b/myproposal.h +index b35b2b8..a608d27 100644 +--- a/myproposal.h ++++ b/myproposal.h +@@ -140,6 +140,28 @@ + "hmac-sha1-96," \ + "hmac-md5-96" + ++#define KEX_DEFAULT_KEX_FIPS \ ++ KEX_ECDH_METHODS \ ++ KEX_SHA256_METHODS \ ++ "diffie-hellman-group-exchange-sha1," \ ++ "diffie-hellman-group14-sha1" ++#define KEX_FIPS_ENCRYPT \ ++ "aes128-ctr,aes192-ctr,aes256-ctr," \ ++ "aes128-cbc,3des-cbc," \ ++ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" ++#ifdef HAVE_EVP_SHA256 ++#define KEX_FIPS_MAC \ ++ "hmac-sha1," \ ++ "hmac-sha2-256," \ ++ "hmac-sha2-512," \ ++ "hmac-sha1-etm@openssh.com," \ ++ "hmac-sha2-256-etm@openssh.com," \ ++ "hmac-sha2-512-etm@openssh.com" ++#else ++#define KEX_FIPS_MAC \ ++ "hmac-sha1" ++#endif ++ + #else + + #define KEX_SERVER_KEX \ +diff --git a/ssh.c b/ssh.c +index 26e9681..a0a7c29 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -75,6 +75,8 @@ + #include + #include + #endif ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + #include "openbsd-compat/sys-queue.h" + +@@ -433,6 +435,13 @@ main(int ac, char **av) + sanitise_stdfd(); + + __progname = ssh_get_progname(av[0]); ++ SSLeay_add_all_algorithms(); ++ if (access("/etc/system-fips", F_OK) == 0) ++ if (! FIPSCHECK_verify(NULL, NULL)) ++ if (FIPS_mode()) ++ fatal("FIPS integrity verification test failed."); ++ else ++ logit("FIPS integrity verification test failed."); + + #ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ +@@ -510,6 +519,9 @@ main(int ac, char **av) + "ACD:E:F:I:KL:MNO:PQ:R: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': +@@ -841,7 +853,6 @@ main(int ac, char **av) + host_arg = xstrdup(host); + + #ifdef WITH_OPENSSL +- OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + #endif + +@@ -997,6 +1008,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); + +@@ -1069,6 +1084,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, addrs, &hostaddr, options.port, + options.address_family, options.connection_attempts, +diff --git a/sshconnect2.c b/sshconnect2.c +index efe6158..5631f39 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -46,6 +46,8 @@ + #include + #endif + ++#include ++ + #include "openbsd-compat/sys-queue.h" + + #include "xmalloc.h" +@@ -171,20 +173,25 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + + #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 (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ /* 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; ++ 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); ++ 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 +@@ -196,6 +203,10 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + 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]); +@@ -211,7 +222,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + 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] = + compat_pkalg_proposal(options.hostkeyalgorithms); +@@ -223,9 +238,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; ++ else if (FIPS_mode()) ++ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; ++ + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( + myproposal[PROPOSAL_KEX_ALGS]); +- + #ifdef GSSAPI + /* If we've got GSSAPI algorithms, then we also support the + * 'null' hostkey, as a last resort */ +diff --git a/sshd.c b/sshd.c +index db23ce2..3ce59f0 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -66,6 +66,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -76,6 +77,8 @@ + #include + #include + #include ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -1479,6 +1482,18 @@ main(int ac, char **av) + #endif + __progname = ssh_get_progname(av[0]); + ++ SSLeay_add_all_algorithms(); ++ if (access("/etc/system-fips", F_OK) == 0) ++ if (! FIPSCHECK_verify(NULL, NULL)) { ++ openlog(__progname, LOG_PID, LOG_AUTHPRIV); ++ if (FIPS_mode()) { ++ syslog(LOG_CRIT, "FIPS integrity verification test failed."); ++ cleanup_exit(255); ++ } ++ else ++ syslog(LOG_INFO, "FIPS integrity verification test failed."); ++ closelog(); ++ } + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = ac; + rexec_argc = ac; +@@ -1630,7 +1645,7 @@ main(int ac, char **av) + else + closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); + +-#ifdef WITH_OPENSSL ++#if 0 /* FIPS */ + OpenSSL_add_all_algorithms(); + #endif + +@@ -1816,6 +1831,10 @@ main(int ac, char **av) + debug("private host key: #%d type %d %s", i, keytype, + key_type(key ? key : pubkey)); + } ++ 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; +@@ -1982,6 +2001,10 @@ main(int ac, char **av) + /* Reinitialize the log (because of the fork above). */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + ++ if (FIPS_mode()) { ++ logit("FIPS mode initialized"); ++ } ++ + /* Chdir to the root directory so that the current disk can be + unmounted if desired. */ + if (chdir("/") == -1) +@@ -2541,6 +2564,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]); +@@ -2550,6 +2576,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] = +@@ -2560,6 +2589,8 @@ do_ssh2_kex(void) + } + if (options.kex_algorithms != NULL) + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; ++ else if (FIPS_mode()) ++ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; + + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( + myproposal[PROPOSAL_KEX_ALGS]); +@@ -2586,10 +2617,14 @@ do_ssh2_kex(void) + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) + orig = NULL; + +- if (options.gss_keyex) +- gss = ssh_gssapi_server_mechanisms(); +- else +- gss = NULL; ++ if (options.gss_keyex) { ++ if (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ gss = ssh_gssapi_server_mechanisms(); ++ } ++ } + + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); +diff --git a/sshkey.c b/sshkey.c +index f078e11..5e3d97f 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "crypto_api.h" + +@@ -1523,6 +1524,8 @@ rsa_generate_private_key(u_int bits, RSA **rsap) + } + if (!BN_set_word(f4, RSA_F4) || + !RSA_generate_key_ex(private, bits, f4, NULL)) { ++ if (FIPS_mode()) ++ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } diff --git a/openssh-6.7p1-ldap.patch b/openssh-6.7p1-ldap.patch new file mode 100644 index 0000000..51faad6 --- /dev/null +++ b/openssh-6.7p1-ldap.patch @@ -0,0 +1,2674 @@ +diff --git a/HOWTO.ldap-keys b/HOWTO.ldap-keys +new file mode 100644 +index 0000000..dd5f5cc +--- /dev/null ++++ b/HOWTO.ldap-keys +@@ -0,0 +1,108 @@ ++ ++HOW TO START ++ ++1) configure LDAP server ++ * Use LDAP server documentation ++2) add appropriate LDAP schema ++ * For OpenLDAP or SunONE Use attached schema, otherwise you have to create it. ++ * LDAP user entry ++ User entry: ++ - attached to the 'ldapPublicKey' objectclass ++ - attached to the 'posixAccount' objectclass ++ - with a filled 'sshPublicKey' attribute ++3) insert users into LDAP ++ * Use LDAP Tree management tool as useful ++ * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema and the additionnal lpk.schema. ++ * Example: ++ dn: uid=captain,ou=commanders,dc=enterprise,dc=universe ++ objectclass: top ++ objectclass: person ++ objectclass: organizationalPerson ++ objectclass: posixAccount ++ objectclass: ldapPublicKey ++ description: Jonathan Archer ++ userPassword: Porthos ++ cn: onathan Archer ++ sn: onathan Archer ++ uid: captain ++ uidNumber: 1001 ++ gidNumber: 1001 ++ homeDirectory: /home/captain ++ sshPublicKey: ssh-rss AAAAB3.... =captain@universe ++ sshPublicKey: command="kill -9 1" ssh-rss AAAAM5... ++4) on the ssh side set in sshd_config ++ * Set up the backend ++ AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper ++ AuthorizedKeysCommandUser ++ * Do not forget to set ++ PubkeyAuthentication yes ++ * Swith off unnecessary auth methods ++5) confugure ldap.conf ++ * Default ldap.conf is placed in /etc/ssh ++ * The configuration style is the same as other ldap based aplications ++6) if necessary edit ssh-ldap-wrapper ++ * There is a possibility to change ldap.conf location ++ * There are some debug options ++ * Example ++ /usr/libexec/openssh -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt ++ ++HOW TO MIGRATE FROM LPK ++ ++1) goto HOW TO START 4) .... the ldap schema is the same ++ ++2) convert the group requests to the appropriate LDAP requests ++ ++HOW TO SOLVE PROBLEMS ++ ++1) use debug in sshd ++ * /usr/sbin/sshd -d -d -d -d ++2) use debug in ssh-ldap-helper ++ * ssh-ldap-helper -d -d -d -d -s ++3) use tcpdump ... other ldap client etc. ++ ++ADVANTAGES ++ ++1) Blocking an user account can be done directly from LDAP (if sshd is using PubkeyAuthentication + AuthorizedKeysCommand with ldap only). ++ ++DISADVANTAGES ++ ++1) LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP ++ allows write to users dn, somebody could replace some user's public key by his own and impersonate some ++ of your users in all your server farm -- be VERY CAREFUL. ++2) With incomplete PKI the MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login ++ as the impersonated user. ++3) If LDAP server is down there may be no fallback on passwd auth. ++ ++MISC. ++ ++1) todo ++ * Possibility to reuse the ssh-ldap-helper. ++ * Tune the LDAP part to accept all possible LDAP configurations. ++ ++2) differences from original lpk ++ * No LDAP code in sshd. ++ * Support for various LDAP platforms and configurations. ++ * LDAP is configured in separate ldap.conf file. ++ ++3) 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 ) ++ ++4) contributors/ideas/greets ++ - Eric AUGE ++ - Andrea Barisani ++ - Falk Siemonsmeier. ++ - Jacob Rief. ++ - Michael Durchgraf. ++ - frederic peters. ++ - Finlay dobbie. ++ - Stefan Fisher. ++ - Robin H. Johnson. ++ - Adrian Bridgett. ++ ++5) Author ++ Jan F. Chadima ++ +diff --git a/Makefile.in b/Makefile.in +index 06be3d5..f02aa1e 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh + ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign ++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper ++SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +@@ -61,8 +63,9 @@ XAUTH_PATH=@XAUTH_PATH@ + LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ + EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ ++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) 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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) + + LIBOPENSSH_OBJS=\ + ssherr.o \ +@@ -108,8 +111,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ + sandbox-seccomp-filter.o sandbox-capsicum.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-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-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-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap-helper.8.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-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ssh-ldap-helper.8 ssh-ldap.conf.5 + MANTYPE = @MANTYPE@ + + CONFIGFILES=sshd_config.out ssh_config.out moduli.out +@@ -180,6 +183,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readco + 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) + +@@ -295,6 +301,10 @@ install-files: + $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) + $(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) ; \ ++ $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ ++ 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 +@@ -311,6 +321,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 +@@ -340,6 +354,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 \ +@@ -403,6 +424,8 @@ uninstall: + -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) + -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) ++ -rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT) ++ -rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT) + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 +@@ -414,6 +437,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 + + regress-prep: +diff --git a/configure.ac b/configure.ac +index 67c4486..6553074 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1569,6 +1569,106 @@ if test "x$use_pie" != "xno"; then + fi + fi + ++# 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([ \ + Blowfish_initstate \ +diff --git a/ldap-helper.c b/ldap-helper.c +new file mode 100644 +index 0000000..e95a94a +--- /dev/null ++++ b/ldap-helper.c +@@ -0,0 +1,155 @@ ++/* $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 in 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 { ++ usage(); ++ 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) { return NULL; } ++void buffer_put_string(Buffer *b, const void *f, u_int l) {} ++ +diff --git a/ldap-helper.h b/ldap-helper.h +new file mode 100644 +index 0000000..14cb29a +--- /dev/null ++++ b/ldap-helper.h +@@ -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 --git a/ldap.conf b/ldap.conf +new file mode 100644 +index 0000000..42e38d3 +--- /dev/null ++++ b/ldap.conf +@@ -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 --git a/ldapbody.c b/ldapbody.c +new file mode 100644 +index 0000000..3029108 +--- /dev/null ++++ b/ldapbody.c +@@ -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=%s)(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); ++ free (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 ++ (void) 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(options.account_class) + strlen (user); ++ if (options.ssh_filter != NULL) ++ bufflen += strlen (options.ssh_filter); ++ buffer = xmalloc (bufflen); ++ snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, options.account_class, 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)); ++ free (buffer); ++ return; ++ } ++ ++ /* free */ ++ free (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 --git a/ldapbody.h b/ldapbody.h +new file mode 100644 +index 0000000..665dca2 +--- /dev/null ++++ b/ldapbody.h +@@ -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 --git a/ldapconf.c b/ldapconf.c +new file mode 100644 +index 0000000..b49cae6 +--- /dev/null ++++ b/ldapconf.c +@@ -0,0 +1,722 @@ ++/* $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, ++ lAccountClass, 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 }, ++ { "AccountClass", lAccountClass }, ++ { 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; ++} ++ ++/* Characters considered whitespace in strsep calls. */ ++#define WHITESPACE " \t\r\n" ++ ++/* return next token in configuration line */ ++static char * ++ldap_strdelim(char **s) ++{ ++ char *old; ++ int wspace = 0; ++ ++ if (*s == NULL) ++ return NULL; ++ ++ old = *s; ++ ++ *s = strpbrk(*s, WHITESPACE); ++ if (*s == NULL) ++ return (old); ++ ++ *s[0] = '\0'; ++ ++ /* Skip any extra whitespace after first token */ ++ *s += strspn(*s + 1, WHITESPACE) + 1; ++ if (*s[0] == '=' && !wspace) ++ *s += strspn(*s + 1, WHITESPACE) + 1; ++ ++ return (old); ++} ++ ++/* ++ * 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 = ldap_strdelim(&s)) == NULL) ++ return 0; ++ /* Ignore leading whitespace. */ ++ if (*keyword == '\0') ++ keyword = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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 = ldap_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) ++ *intptr = value; ++ break; ++ ++ case lSSLPath: ++ charptr = &options.sslpath; ++ goto parse_string; ++ ++ case lSSL: ++ intptr = &options.ssl; ++ arg = ldap_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 = ldap_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 = ldap_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) ++ *intptr = value; ++ 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 lAccountClass: ++ charptr = &options.account_class; ++ goto parse_string; ++ ++ 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 = ldap_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; ++ options.account_class = 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 = ""; ++ if (options.account_class == NULL) ++ options.account_class = "posixAccount"; ++} ++ ++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); ++ dump_cfg_string(lAccountClass, options.logdir); ++} ++ +diff --git a/ldapconf.h b/ldapconf.h +new file mode 100644 +index 0000000..2cb550c +--- /dev/null ++++ b/ldapconf.h +@@ -0,0 +1,72 @@ ++/* $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; ++ char *account_class; ++} 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 --git a/ldapincludes.h b/ldapincludes.h +new file mode 100644 +index 0000000..8539bdc +--- /dev/null ++++ b/ldapincludes.h +@@ -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 --git a/ldapmisc.c b/ldapmisc.c +new file mode 100644 +index 0000000..de23c0c +--- /dev/null ++++ b/ldapmisc.c +@@ -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 --git a/ldapmisc.h b/ldapmisc.h +new file mode 100644 +index 0000000..4c271df +--- /dev/null ++++ b/ldapmisc.h +@@ -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 --git a/openssh-lpk-openldap.schema b/openssh-lpk-openldap.schema +new file mode 100644 +index 0000000..c84f90f +--- /dev/null ++++ b/openssh-lpk-openldap.schema +@@ -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 --git a/openssh-lpk-sun.schema b/openssh-lpk-sun.schema +new file mode 100644 +index 0000000..3136673 +--- /dev/null ++++ b/openssh-lpk-sun.schema +@@ -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 --git a/ssh-ldap-helper.8 b/ssh-ldap-helper.8 +new file mode 100644 +index 0000000..5d2d7be +--- /dev/null ++++ b/ssh-ldap-helper.8 +@@ -0,0 +1,79 @@ ++.\" $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-wrapper . ++.Pp ++.Nm ++is not intended to be invoked by the user, but from ++.Xr sshd 8 via ++.Xr ssh-ldap-wrapper . ++.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. ++.El ++.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/ssh-ldap-wrapper b/ssh-ldap-wrapper +new file mode 100644 +index 0000000..cb500aa +--- /dev/null ++++ b/ssh-ldap-wrapper +@@ -0,0 +1,4 @@ ++#!/bin/sh ++ ++exec /usr/libexec/openssh/ssh-ldap-helper -s "$1" ++ +diff --git a/ssh-ldap.conf.5 b/ssh-ldap.conf.5 +new file mode 100644 +index 0000000..f7081b8 +--- /dev/null ++++ b/ssh-ldap.conf.5 +@@ -0,0 +1,379 @@ ++.\" $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). ++.Bl -tag -width Ds ++.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 ++.Dq start_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. ++.It Cm AccountClass ++Specifies the LDAP class used to find user accounts. ++The default is posixAccount. ++.El ++.Sh FILES ++.Bl -tag -width Ds ++.It Pa /etc/ssh/ldap.conf ++Ldap configuration file for ++.Xr ssh-ldap-helper 8 . ++.El ++.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 --git a/openssh.spec b/openssh.spec index 28abea8..86883b1 100644 --- a/openssh.spec +++ b/openssh.spec @@ -63,10 +63,10 @@ %endif # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%define openssh_ver 6.6.1p1 -%define openssh_rel 11.1 +%define openssh_ver 6.7p1 +%define openssh_rel 1 %define pam_ssh_agent_ver 0.9.3 -%define pam_ssh_agent_rel 3 +%define pam_ssh_agent_rel 4 Summary: An open source implementation of SSH protocol versions 1 and 2 Name: openssh @@ -74,8 +74,7 @@ Version: %{openssh_ver} Release: %{openssh_rel}%{?dist}%{?rescue_rel} URL: http://www.openssh.com/portable.html #URL1: http://pamsshagentauth.sourceforge.net -# Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz -Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.6p1.tar.gz +Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc Source2: sshd.pam Source3: sshd.init @@ -103,10 +102,9 @@ Patch102: openssh-5.8p1-getaddrinfo.patch Patch103: openssh-5.8p1-packet.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1402 -Patch200: openssh-6.6p1-audit.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1171248 # record pfs= field in CRYPTO_SESSION audit event -Patch201: openssh-6.6.1p1-audit-pfs.patch +Patch200: openssh-6.7p1-audit.patch # --- pam_ssh-agent --- # make it build reusing the openssh sources @@ -117,13 +115,15 @@ Patch301: pam_ssh_agent_auth-0.9.2-seteuid.patch Patch302: pam_ssh_agent_auth-0.9.2-visibility.patch # don't use xfree (#1024965) Patch303: pam_ssh_agent_auth-0.9.3-no-xfree.patch +# use SSH_DIGEST_* for fingerprint hashes +Patch304: pam_ssh_agent_auth-0.9.3-fingerprint-hash.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) Patch400: openssh-6.6p1-role-mls.patch #https://bugzilla.redhat.com/show_bug.cgi?id=781634 Patch404: openssh-6.6p1-privsep-selinux.patch #?-- unwanted child :( -Patch501: openssh-6.6p1-ldap.patch +Patch501: openssh-6.7p1-ldap.patch #? Patch502: openssh-6.6p1-keycat.patch @@ -143,15 +143,11 @@ Patch608: openssh-6.1p1-askpass-ld.patch Patch609: openssh-5.5p1-x11.patch #? -Patch700: openssh-6.6p1-fips.patch -#? -# drop? Patch701: openssh-5.6p1-exit-deadlock.patch +Patch700: openssh-6.7p1-fips.patch #? Patch702: openssh-5.1p1-askpass-progress.patch #? Patch703: openssh-4.3p2-askpass-grab-info.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=205842 -# drop? Patch704: openssh-5.9p1-edns.patch #? Patch705: openssh-5.1p1-scp-manpage.patch #? @@ -361,7 +357,7 @@ remote ssh-agent instance. The module is most useful for su and sudo service stacks. %prep -%setup -q -a 4 -n openssh-6.6p1 +%setup -q -a 4 #Do not enable by default %if 0 %patch0 -p1 -b .wIm @@ -377,6 +373,7 @@ pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} %patch301 -p1 -b .psaa-seteuid %patch302 -p1 -b .psaa-visibility %patch303 -p1 -b .psaa-xfree +%patch304 -p2 -b .psaa-fingerprint # Remove duplicate headers rm -f $(cat %{SOURCE5}) popd @@ -399,13 +396,8 @@ popd %patch607 -p1 -b .sigpipe %patch608 -p1 -b .askpass-ld %patch609 -p1 -b .x11 -# -# drop? %patch701 -p1 -b .exit-deadlock %patch702 -p1 -b .progress %patch703 -p1 -b .grab-info -# investigate - https://bugzilla.redhat.com/show_bug.cgi?id=205842 -# probably not needed anymore %patch704 -p1 -b .edns -# drop it %patch705 -p1 -b .manpage %patch706 -p1 -b .localdomain %patch707 -p1 -b .redhat %patch708 -p1 -b .entropy @@ -422,15 +414,10 @@ popd %patch902 -p1 -b .ccache_name %patch905 -p1 -b .legacy-ssh-copy-id %patch906 -p1 -b .fromto-remote -%patch907 -p1 -b .CLOCK_BOOTTIME -%patch908 -p1 -b .CVE-2014-2653 -%patch909 -p1 -b .6.6.1 -%patch910 -p1 -b .NI_MAXHOST %patch911 -p1 -b .set_remote_ipaddr %patch912 -p1 -b .utf8-banner %patch913 -p1 -b .partial-success %patch914 -p1 -b .servconf -%patch915 -p1 -b .SIGXFSZ %patch916 -p1 -b .contexts %patch917 -p1 -b .cisco-dh %patch918 -p1 -b .log-in-chroot @@ -439,10 +426,10 @@ popd %patch802 -p1 -b .GSSAPIEnablek5users %patch200 -p1 -b .audit -%patch201 -p1 -b .audit-fps %patch700 -p1 -b .fips -%patch100 -p1 -b .coverity +# FIXME rebase 6.7p1 +# %patch100 -p1 -b .coverity %if 0 # Nothing here yet @@ -751,6 +738,9 @@ getent passwd sshd >/dev/null || \ %endif %changelog +* Tue Jan 20 2015 Petr Lautrbach 6.7p1-1 + 0.9.3-4 +- new upstream release openssh-6.7p1 + * Thu Jan 15 2015 Jakub Jelen 6.6.1p1-11.1 + 0.9.3-3 - error message if scp when directory doesn't exist (#1142223) - parsing configuration file values (#1130733) diff --git a/pam_ssh_agent_auth-0.9.3-fingerprint-hash.patch b/pam_ssh_agent_auth-0.9.3-fingerprint-hash.patch new file mode 100644 index 0000000..6b133ee --- /dev/null +++ b/pam_ssh_agent_auth-0.9.3-fingerprint-hash.patch @@ -0,0 +1,64 @@ +diff --git a/pam_ssh_agent_auth-0.9.3/key.c b/pam_ssh_agent_auth-0.9.3/key.c +index 9555e7e..c17aae6 100644 +--- a/pam_ssh_agent_auth-0.9.3/key.c ++++ b/pam_ssh_agent_auth-0.9.3/key.c +@@ -55,6 +55,7 @@ + #include "uuencode.h" + #include "buffer.h" + #include "log.h" ++#include "digest.h" + + Key * + key_new(int type) +@@ -181,7 +182,7 @@ key_equal(const Key *a, const Key *b) + } + + u_char* +-key_fingerprint_raw(const Key *k, enum fp_type dgst_type, ++key_fingerprint_raw(const Key *k, int dgst_type, + u_int *dgst_raw_length) + { + const EVP_MD *md = NULL; +@@ -194,10 +195,10 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type, + *dgst_raw_length = 0; + + switch (dgst_type) { +- case SSH_FP_MD5: ++ case SSH_DIGEST_MD5: + md = EVP_md5(); + break; +- case SSH_FP_SHA1: ++ case SSH_DIGEST_SHA1: + md = EVP_sha1(); + break; + default: +@@ -302,7 +303,7 @@ key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) + } + + char * +-key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) ++key_fingerprint(const Key *k, int dgst_type, enum fp_rep dgst_rep) + { + char *retval = NULL; + u_char *dgst_raw; +diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c +index dddcba9..8ba6d87 100644 +--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c ++++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c +@@ -43,6 +43,7 @@ + #include "buffer.h" + #include "log.h" + #include "compat.h" ++#include "digest.h" + #include "key.h" + #include "pathnames.h" + #include "misc.h" +@@ -118,7 +119,7 @@ pam_user_key_allowed2(struct passwd *pw, Key *key, char *file) + found_key = 1; + logit("matching key found: file %s, line %lu", + file, linenum); +- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); ++ fp = key_fingerprint(found, SSH_DIGEST_MD5, SSH_FP_HEX); + logit("Found matching %s key: %s", + key_type(found), fp); + free(fp); diff --git a/sources b/sources index fbdb5e4..1215c48 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ 9872ca1983e566ff5a89c240529e223d pam_ssh_agent_auth-0.9.3.tar.bz2 -3e9800e6bca1fbac0eea4d41baa7f239 openssh-6.6p1.tar.gz +3246aa79317b1d23cae783a3bf8275d6 openssh-6.7p1.tar.gz