1 This adds the PubKeyPlugin directive and associated code from
2 SunSSH, allowing an in-process shared library to be called
3 into to check public keys for authentication.
5 --- hpn-ssh-hpn-18.4.2/auth2-pubkey.c.orig
6 +++ hpn-ssh-hpn-18.4.2/auth2-pubkey.c
8 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
9 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
13 + * Copyright 2015 Joyent, Inc.
14 + * Use is subject to license terms.
37 +static const char *RSA_SYM_NAME = "sshd_user_rsa_key_allowed";
38 +static const char *ECDSA_SYM_NAME = "sshd_user_ecdsa_key_allowed";
39 +typedef int (*RSA_SYM)(struct passwd *, RSA *, const char *);
40 +typedef int (*ECDSA_SYM)(struct passwd *, EC_KEY *, const char *);
42 +static const char *UNIV_SYM_NAME = "sshd_user_key_allowed";
43 +typedef int (*UNIV_SYM)(struct passwd *, const char *,
44 + const u_char *, size_t);
47 userauth_pubkey(struct ssh *ssh, const char *method)
54 + * Checks whether or not access is allowed based on a plugin specified
55 + * in sshd_config (PubKeyPlugin).
57 + * Note that this expects a symbol in the loaded library that takes
58 + * the current user (pwd entry), the current RSA key and it's fingerprint.
59 + * The symbol is expected to return 1 on success and 0 on failure.
61 + * While we could optimize this code to dlopen once in the process' lifetime,
62 + * sshd is already a slow beast, so this is really not a concern.
63 + * The overhead is basically a rounding error compared to everything else, and
64 + * it keeps this code minimally invasive.
67 +user_key_allowed_from_plugin(struct passwd *pw, struct sshkey *key)
69 + RSA_SYM rsa_sym = NULL;
70 + ECDSA_SYM ecdsa_sym = NULL;
71 + UNIV_SYM univ_sym = NULL;
74 + void *handle = NULL;
77 + if (options.pubkey_plugin == NULL || pw == NULL || key == NULL ||
78 + (key->type != KEY_RSA &&
79 + key->type != KEY_DSA && key->type != KEY_ECDSA))
82 + handle = dlopen(options.pubkey_plugin, RTLD_NOW);
83 + if (handle == NULL) {
84 + debug("Unable to open library %s: %s", options.pubkey_plugin,
90 + * If we have the new-style universal symbol for checking keys, use
91 + * that instead of the old-style per-key-type symbols.
93 + univ_sym = (UNIV_SYM)dlsym(handle, UNIV_SYM_NAME);
94 + if (univ_sym != NULL) {
96 + const char *type = sshkey_type(key);
98 + if (sshkey_to_blob(key, &blob, &len) != 0) {
99 + debug("failed to convert key to rfc4253 format");
102 + debug("Invoking %s from %s", UNIV_SYM_NAME,
103 + options.pubkey_plugin);
104 + success = (*univ_sym)(pw, type, blob, len);
105 + debug("pubkeyplugin returned: %d", success);
109 + /* Otherwise, continue with the old-style fingerprint symbols. */
110 + fp = sshkey_fingerprint(key, SSH_DIGEST_MD5, SSH_FP_HEX);
112 + debug("failed to generate fingerprint");
115 + if (strncmp(fp, "MD5:", 4) != 0) {
116 + debug("fingerprint not in MD5:hex format");
119 + /* give the plugin the string without leading MD5: */
122 + switch (key->type) {
124 + rsa_sym = (RSA_SYM)dlsym(handle, RSA_SYM_NAME);
125 + if (rsa_sym == NULL) {
126 + debug("Unable to resolve symbol %s: %s", RSA_SYM_NAME,
130 + debug2("Invoking %s from %s", RSA_SYM_NAME,
131 + options.pubkey_plugin);
132 + success = (*rsa_sym)(pw, key->rsa, argfp);
135 + ecdsa_sym = (ECDSA_SYM)dlsym(handle, ECDSA_SYM_NAME);
136 + if (ecdsa_sym == NULL) {
137 + debug("Unable to resolve symbol %s: %s", ECDSA_SYM_NAME,
141 + debug2("Invoking %s from %s", ECDSA_SYM_NAME,
142 + options.pubkey_plugin);
143 + success = (*ecdsa_sym)(pw, key->ecdsa, argfp);
146 + debug2("user_key_plugins only support RSA and ECDSA keys");
149 + debug("pubkeyplugin returned: %d", success);
152 + if (handle != NULL) {
161 + verbose("Found matching %s key: %s", sshkey_type(key), fp);
172 * Check whether key authenticates and authorises the user.
175 sshauthopt_free(opts);
178 + success = user_key_allowed_from_plugin(pw, key);
182 if ((success = user_key_command_allowed2(pw, key, remote_ip,
183 remote_host, conn_id, rdomain, &opts)) != 0)
185 --- hpn-ssh-hpn-18.4.2/servconf.c.orig
186 +++ hpn-ssh-hpn-18.4.2/servconf.c
189 options->pam_service_per_authmethod = 1;
191 + options->pubkey_plugin = NULL;
194 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
196 sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
197 sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
198 sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
200 sDeprecated, sIgnore, sUnsupported
204 { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
205 { "rdomain", sRDomain, SSHCFG_ALL },
206 { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
207 + { "pubkeyplugin", sPubKeyPlugin, SSHCFG_ALL },
208 { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
209 { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
210 { "channeltimeout", sChannelTimeout, SSHCFG_ALL },
211 @@ -2705,6 +2708,18 @@
215 + case sPubKeyPlugin:
217 + * Can't use parse_filename, as we need to support plain
218 + * names which dlopen will find on our lib path.
220 + arg = strdelim(&str);
221 + if (!arg || *arg == '\0')
222 + fatal("%s line %d: missing file name.",
223 + filename, linenum);
224 + options->pubkey_plugin = xstrdup(arg);
230 --- hpn-ssh-hpn-18.4.2/servconf.h.orig
231 +++ hpn-ssh-hpn-18.4.2/servconf.h
234 int fingerprint_hash;
235 int expose_userauth_info;
236 + char *pubkey_plugin;
237 u_int64_t timing_secret;
239 int required_rsa_size; /* minimum size of RSA keys */