Feature patch: key name/patterns in authorized_keys2 [e.g., Kerberos principal names] (was Re: Adding 'name' key types)
Nicolas Williams
Nicolas.Williams at ubsw.com
Wed Jul 4 04:57:39 EST 2001
Ok, to follow up to myself, here's a much more featureful, complete and
tested patch.
This patch (to OpenSSH 2.9p2) adds:
- ssh-ext-named key entry type for authorized_keys2 files
- ssh-ext-name-pat key entry type for authorized_keys2 files
- deny-access option for authorized_keys2 files
- SSH_AUTH_EXT_NAME environment variable added by sshd when
- SSH_AUTH_EXT_NAME_TYPE similar
Now you can have entries like this in you authorized_keys2 files:
ssh-ext-named:krb5 someuser at SOMEREALM
deny-access ssh-ext-named:krb5 joe/superroot at SOMEREALM
ssh-ext-name-pat:krb5 */superroot at SOMERALM
Double quotes can be used when key names contain whitespace.
So far I have only modified simon at sxw.org.uk's GSS-API patches for
OpenSSH to support the use of 'krb5' key names in authorized_keys2
files.
I really hope that this feature or a variation thereof will find its way
into OpenSSH. In conjunction with Kerberos (IV or V) it can be extremely
useful:
- key management is simplified: key management is done at the KDC and
there is no need to edit authorized_keys2 files all over to revoke
keys!
- authorized_keys2 is much more featureful than .klogin and .k5login
are, regardless of Kerberos implementation source (KTH, Heimdal, MIT,
SEAM, all implement pretty much the same all-or-nothing
.klogin/.k5login functionality).
A similar patch of gss-serv.c:ssh_gssapi_gsi_userok() to support the
use of 'gsi' key names in authorized_keys2 would be trivial.
A similar patch to auth-krb4.c:auth_krb4() to support the use of 'krb4'
key names would be trivial, but I could not test such a patch.
A question, in my mind, is whether the krb4/gss:krb5/gss:gsi ssh_*userok()
code should require both, authorized_keys2 check *and* the underlying
mechanism userok() check to pass, or either, or what. My patch to
gss-serv.c:ssh_gssapi_krb5_userok() requires either check to pass.
Below you should find two versions of this patch, one against OpenSSH
2.9p2, the other against 2.9p2 + simon at sxw.org.uk's GSS-API patches.
NOTE: I did not strive too hard to keep to the code style of OpenSSH.
Point me a the description of the OpenSSH code style and I'll
modify my patch accordingly.
Files modified:
- key.h
- added KEY_NAME key type
- added KEY_NAME_PAT key type
- added name, name_len and name_type fields to the Key struct
- added prototype for key_match()
- key.c
- added initialization/finalization of new Key fields to key_new()/key_free()
- added named/pattern key type support to a variety of functions,
including key_read() and key_write(), among others
- added key_match() implementation
- auth-options.h
- added void auth_set_key_env(Key *) prototype
- auth-options.c
- added auth_set_key_env() implementation
- modified auth_parse_options() to return (-1) when new deny-access
option is encountered
- auth-rsa.c
- modified auth_parse_options() return value check according to the
change made to auth_parse_options()
- auth2.c
- modified user_key_allowed() to:
- try key_match() if key_equal() fails
- check the result of auth_parse_options() for negative, 0, or
positive values.
- modified userauth_pubkey() to check for positive return value of
user_key_allowed()
- sshd.8
- added documentation
- gss-serv.c
- modified ssh_gssapi_krb5_userok() to build a Key struct and
call user_key_allowed()
Nico
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-
********************************************************************************
Index: 2_9_p2.1/sshd.8
--- 2_9_p2.1/sshd.8 Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/h/28_sshd.8 1.1 644)
+++ 2_9_p2_w_named_keys.2/sshd.8 Tue, 03 Jul 2001 14:20:28 -0400 willian (OpenSSH/h/28_sshd.8 1.1.1.1 644)
@@ -852,7 +852,8 @@
.Pa $HOME/.ssh/authorized_keys2
file lists the DSA and RSA keys that are
permitted for public key authentication (PubkeyAuthentication)
-in protocol version 2.
+in protocol version 2. It can also list key names or key patterns
+for external authentication systems, such as krb4, krb5, gsi, etc...
.Pp
Each line of the file contains one
key (empty lines and lines starting with a
@@ -873,7 +874,19 @@
For protocol version 2 the keytype is
.Dq ssh-dss
or
-.Dq ssh-rsa .
+.Dq ssh-rsa
+or
+.Dq ssh-ext-named:<keytype>
+or
+.Dq ssh-ext-name-pat:<keytype> .
+.Pp
+Named keys and key name patterns follow the latter two, in double
+quotes if they contain whitespace. Named key types may include:
+.Dq krb4 ,
+.Dq krb5
+and/or
+.Dq gsi ,
+depending on what features are compiled in to OpenSSH.
.Pp
Note that lines in this file are usually several hundred bytes long
(because of the size of the RSA key modulus).
@@ -930,6 +943,10 @@
Environment variables set this way
override other default environment values.
Multiple options of this type are permitted.
+.It Cm deny-access
+This option ends authorized_keys2 processing if the key matches. This
+option is only really useful with named key and named key pattern
+entries.
.It Cm no-port-forwarding
Forbids TCP/IP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
Index: 2_9_p2.1/key.h
--- 2_9_p2.1/key.h Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/j/7_key.h 1.1 644)
+++ 2_9_p2_w_named_keys.2/key.h Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/j/7_key.h 1.1.1.1 644)
@@ -34,7 +34,9 @@
KEY_RSA1,
KEY_RSA,
KEY_DSA,
- KEY_UNSPEC
+ KEY_UNSPEC,
+ KEY_NAME,
+ KEY_NAME_PAT
};
enum fp_type {
SSH_FP_SHA1,
@@ -48,12 +50,16 @@
int type;
RSA *rsa;
DSA *dsa;
+ u_char *name;
+ u_int name_len;
+ char *name_type;
};
Key *key_new(int type);
Key *key_new_private(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
+int key_match(Key *a, Key *b);
char *key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
Index: 2_9_p2.1/key.c
--- 2_9_p2.1/key.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/j/8_key.c 1.1 644)
+++ 2_9_p2_w_named_keys.2/key.c Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/j/8_key.c 1.1.1.1 644)
@@ -56,6 +56,9 @@
k->type = type;
k->dsa = NULL;
k->rsa = NULL;
+ k->name = NULL;
+ k->name_len = 0;
+ k->name_type = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -72,6 +75,8 @@
dsa->pub_key = BN_new();
k->dsa = dsa;
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
case KEY_UNSPEC:
break;
default:
@@ -119,6 +124,14 @@
DSA_free(k->dsa);
k->dsa = NULL;
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
+ if (k->name != NULL)
+ xfree(k->name);
+ k->name_len = 0;
+ if (k->name_type != NULL)
+ xfree(k->name_type);
+ break;
case KEY_UNSPEC:
break;
default:
@@ -130,8 +143,9 @@
int
key_equal(Key *a, Key *b)
{
- if (a == NULL || b == NULL || a->type != b->type)
+ if (a == NULL || b == NULL || a->type != b->type) {
return 0;
+ }
switch (a->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -146,12 +160,67 @@
BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
break;
+ case KEY_NAME:
+ if ((a->name_type == NULL && b->name_type == NULL) ||
+ (a->name_type == b->name_type))
+ return (a->name_len == b->name_len) &&
+ (memcmp(a->name, b->name, a->name_len) == 0);
+ if (a->name_type == NULL || b->name_type == NULL)
+ return 0;
+ if (strcmp(a->name_type, b->name_type) == 0)
+ return (a->name_len == b->name_len) &&
+ (memcmp(a->name, b->name, a->name_len) == 0);
+ break;
+ case KEY_NAME_PAT:
+ return 0;
+ break;
default:
fatal("key_equal: bad key type %d", a->type);
break;
}
return 0;
}
+int
+key_match(Key *a, Key *b)
+{
+ debug3("key_match: trying to match %x and %x", a, b);
+ if (a == NULL || b == NULL)
+ return 0;
+
+ debug3("key_match: trying to match key types %d and %d -- KEY_NAME_PAT == %d", a->type, b->type, KEY_NAME_PAT);
+ /* One key must be a name pattern, the other must be a name */
+ if (!(a->type == KEY_NAME_PAT && b->type == KEY_NAME) &&
+ !(b->type == KEY_NAME_PAT && a->type == KEY_NAME))
+ return 0;
+
+ /* Both keys must have name types, or both must not */
+ /* or one key must have '*' as its name type */
+ if ((a->name_type == NULL && b->name_type != NULL) ||
+ (b->name_type == NULL && a->name_type != NULL)) {
+
+ debug3("key_match: foo");
+ if (a->name_type != NULL && *(a->name_type) != '*')
+ return 0;
+ if (b->name_type != NULL && *(b->name_type) != '*')
+ return 0;
+ }
+
+ /* Name type "*" matches any name type */
+ /* Otherwise name types must match */
+ if ((a->name_type != NULL && strcmp(a->name_type, b->name_type) != 0) &&
+ (*(a->name_type) != '*' || *(b->name_type) != '*')) {
+ debug3("key_match: a->name_type == %s", a->name_type ? a->name_type : "");
+ debug3("key_match: b->name_type == %s", b->name_type ? b->name_type : "");
+ return 0;
+ }
+
+ debug3("key_match: trying to match %s WITH %s", a->name, b->name);
+ if (a->type == KEY_NAME_PAT)
+ return match_pattern(b->name, a->name);
+ else
+ return match_pattern(a->name, b->name);
+}
+
u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
@@ -160,7 +229,7 @@
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
- int len = 0;
+ u_int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
@@ -363,11 +432,12 @@
{
Key *k;
int success = -1;
- char *cp, *space;
+ char *cp, *space, *name_type;
int len, n, type;
u_int bits;
- u_char *blob;
+ u_char *blob = NULL;
+ name_type = NULL;
cp = *cpp;
switch(ret->type) {
@@ -390,6 +460,8 @@
case KEY_UNSPEC:
case KEY_RSA:
case KEY_DSA:
+ case KEY_NAME:
+ case KEY_NAME_PAT:
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: no space");
@@ -397,6 +469,17 @@
}
*space = '\0';
type = key_type_from_name(cp);
+ if ((type == KEY_NAME) || (type == KEY_NAME_PAT)) {
+ char * colon = NULL;
+
+ colon = strchr(cp, ':');
+
+ debug3("key_read: handling named key or pattern (%d), %s, colon at %x", type, cp, colon);
+ if (colon != NULL && *(++colon) != '\0') {
+ name_type = xstrdup(colon);
+ } else
+ name_type == NULL;
+ }
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: no key found");
@@ -410,30 +493,80 @@
if (ret->type == KEY_UNSPEC) {
ret->type = type;
} else if (ret->type != type) {
- /* is a key, but different type */
- debug3("key_read: type mismatch");
- return 0;
+ if (! ((ret->type == KEY_NAME) &&
+ type == KEY_NAME_PAT)) {
+ /* is a key, but different type */
+ debug3("key_read: type mismatch");
+ return 0;
+ }
+ ret->type = type;
}
- len = 2*strlen(cp);
- blob = xmalloc(len);
- n = uudecode(cp, blob, len);
- if (n < 0) {
- error("key_read: uudecode %s failed", cp);
- return -1;
+ debug3("key_read: here -- ret->type == %d", ret->type);
+ if ((ret->type == KEY_NAME) || (ret->type == KEY_NAME_PAT)) {
+ char *quote, *newline;
+ debug3("key_read: reading named key %s", cp);
+ if (cp == NULL || *cp == '\0')
+ return 0;
+ if (*cp == '"') {
+ quote = strchr(++cp, '"');
+ if (quote == NULL) {
+ debug3("key_read: missing quote");
+ return 0;
+ }
+ *quote = '\0';
+ }
+ newline = strchr(cp, '\n');
+ if (newline != NULL)
+ *newline = '\0';
+ debug3("key_read: reading named key %s", cp);
+ k = key_new(ret->type);
+ k->name = (unsigned char *) xstrdup(cp);
+ k->name_len = strlen(cp);
+ k->name_type = name_type;
+ if (newline !=NULL)
+ *newline = '\n';
+ if (quote !=NULL)
+ *quote = '"';
+ debug3("key_read: read named key %s", k->name_type);
+ } else {
+ len = 2*strlen(cp);
+ blob = xmalloc(len);
+ n = uudecode(cp, blob, len);
+ if (n < 0) {
+ error("key_read: uudecode %s failed", cp);
+ return -1;
+ }
+ debug3("key_read: reading uuencoded key %s", blob);
+ k = key_from_blob(blob, n);
}
- k = key_from_blob(blob, n);
if (k == NULL) {
error("key_read: key_from_blob %s failed", cp);
return -1;
}
- xfree(blob);
+ if (blob != NULL)
+ xfree(blob);
if (k->type != type) {
- error("key_read: type mismatch: encoding error");
- key_free(k);
- return -1;
+ if (! ((ret->type == KEY_NAME) &&
+ type == KEY_NAME_PAT)) {
+ error("key_read: type mismatch: encoding error");
+ key_free(k);
+ return -1;
+ }
}
/*XXXX*/
- if (ret->type == KEY_RSA) {
+ if ((ret->type == KEY_NAME) || (ret->type == KEY_NAME_PAT)) {
+ /*
+ if (ret->name != NULL)
+ xfree(ret->name);
+ */
+ ret->name = k->name;
+ ret->name_len = k->name_len;
+ ret->name_type = k->name_type;
+ k->name = NULL;
+ k->name_type = NULL;
+ k->name_len = 0;
+ success = 1;
+ } else if (ret->type == KEY_RSA) {
if (ret->rsa != NULL)
RSA_free(ret->rsa);
ret->rsa = k->rsa;
@@ -487,7 +620,7 @@
}
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
- int len, n;
+ u_int len, n;
u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
@@ -498,6 +631,14 @@
}
xfree(blob);
xfree(uu);
+ } else if (key->type == KEY_NAME && key->name != NULL &&
+ key->name_len) {
+
+ fprintf(f, "%s ", key_ssh_name(key));
+ if (key->name_type != NULL)
+ fprintf(f, ":%s", key->name_type);
+ else
+ fprintf(f, " \"%.*s\"", key->name, key->name_len);
}
return success;
}
@@ -514,6 +655,12 @@
case KEY_DSA:
return "DSA";
break;
+ case KEY_NAME:
+ return "Named";
+ break;
+ case KEY_NAME_PAT:
+ return "Name_Pattern";
+ break;
}
return "unknown";
}
@@ -527,6 +674,12 @@
case KEY_DSA:
return "ssh-dss";
break;
+ case KEY_NAME:
+ return "ssh-ext-named";
+ break;
+ case KEY_NAME_PAT:
+ return "ssh-ext-name-pat";
+ break;
}
return "ssh-unknown";
}
@@ -604,6 +757,16 @@
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
+ n = key_new(k->type);
+ n->name_len = k->name_len;
+ n->name = xmalloc(k->name_len);
+ memcpy(n->name, k->name, n->name_len);
+ if (k->name_type) {
+ n->name_type = xstrdup(k->name_type);
+ }
+ break;
default:
fatal("key_from_private: unknown type %d", k->type);
break;
@@ -624,7 +787,16 @@
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
return KEY_DSA;
+ } else if (strcmp(name, "ssh-ext-named") == 0){
+ return KEY_NAME;
+ } else if (strncmp(name, "ssh-ext-named:", strlen("ssh-ext-named:")) == 0){
+ return KEY_NAME;
+ } else if (strcmp(name, "ssh-ext-name-pat") == 0){
+ return KEY_NAME_PAT;
+ } else if (strncmp(name, "ssh-ext-name-pat:", strlen("ssh-ext-name-pat:")) == 0){
+ return KEY_NAME_PAT;
}
+
debug2("key_type_from_name: unknown key type '%s'", name);
return KEY_UNSPEC;
}
Index: 2_9_p2.1/auth2.c
--- 2_9_p2.1/auth2.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/6_auth2.c 1.1 644)
+++ 2_9_p2_w_named_keys.2/auth2.c Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/k/6_auth2.c 1.1.1.1 644)
@@ -491,7 +491,7 @@
buffer_dump(&b);
#endif
/* test for correct signature */
- if (user_key_allowed(authctxt->pw, key) &&
+ if (user_key_allowed(authctxt->pw, key) > 0 &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
@@ -508,7 +508,7 @@
* if a user is not allowed to login. is this an
* issue? -markus
*/
- if (user_key_allowed(authctxt->pw, key)) {
+ if (user_key_allowed(authctxt->pw, key) > 0) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
@@ -768,19 +768,36 @@
continue;
}
}
- if (key_equal(found, key) &&
- auth_parse_options(pw, options, file, linenum) == 1) {
- found_key = 1;
- debug("matching key found: file %s, line %ld",
- file, linenum);
+ if (key_equal(found, key)) {
+ found_key = auth_parse_options(pw, options, file, linenum);
+ if (found_key == 0)
+ continue;
+ break;
+ }
+ if (key_match(found, key)) {
+ found_key = auth_parse_options(pw, options, file, linenum);
+ if (found_key == 0)
+ continue;
+ /* Special treatment for key name patterns belongs here */
break;
}
}
+
+done:
restore_uid();
fclose(f);
key_free(found);
- if (!found_key)
+ if (found_key > 0) {
+ debug("matching key found: file %s, line %ld",
+ file, linenum);
+ auth_set_key_env(key);
+ }
+ if (found_key == 0)
debug2("key not found");
+ if (found_key < 0) {
+ debug("user_key_allowed: matching deny key found: "
+ "file %s, line %ld", file, linenum);
+ }
return found_key;
}
Index: 2_9_p2.1/auth-rsa.c
--- 2_9_p2.1/auth-rsa.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/15_auth-rsa.c 1.1 644)
+++ 2_9_p2_w_named_keys.2/auth-rsa.c Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/k/15_auth-rsa.c 1.1.1.1 644)
@@ -259,7 +259,7 @@
* If our options do not allow this key to be used,
* do not send challenge.
*/
- if (!auth_parse_options(pw, options, file, linenum))
+ if (auth_parse_options(pw, options, file, linenum) < 1)
continue;
/* Perform the challenge-response dialog for this key. */
Index: 2_9_p2.1/auth-options.h
--- 2_9_p2.1/auth-options.h Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/21_auth-optio 1.1 644)
+++ 2_9_p2_w_named_keys.2/auth-options.h Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/k/21_auth-optio 1.1.1.1 644)
@@ -16,6 +16,8 @@
#ifndef AUTH_OPTIONS_H
#define AUTH_OPTIONS_H
+#include "key.h"
+
/* Linked list of custom environment strings */
struct envstring {
struct envstring *next;
@@ -37,6 +39,9 @@
int
auth_parse_options(struct passwd *pw, char *options, char *file,
u_long linenum);
+
+void
+auth_set_key_env(Key *k);
/* reset options flags */
void auth_clear_options(void);
Index: 2_9_p2.1/auth-options.c
--- 2_9_p2.1/auth-options.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/22_auth-optio 1.1 644)
+++ 2_9_p2_w_named_keys.2/auth-options.c Tue, 03 Jul 2001 13:57:30 -0400 willian (OpenSSH/k/22_auth-optio 1.1.1.1 644)
@@ -55,8 +55,43 @@
channel_clear_permitted_opens();
}
+void auth_set_key_env(Key *k)
+{
+ struct envstring *new_env;
+ char *s;
+ int len;
+
+ if (k->type != KEY_NAME)
+ return;
+
+ len = strlen("SSH_AUTH_EXT_NAME=");
+ len += k->name_len + 1;
+ s = xmalloc(len);
+ snprintf(s, len, "SSH_AUTH_EXT_NAME=%.*s", k->name_len, k->name);
+ debug3("auth_set_key_env: Adding to the environment: %.*s", len, s);
+ new_env = xmalloc(sizeof(struct envstring));
+ new_env->s = s;
+ new_env->next = custom_environment;
+ custom_environment = new_env;
+
+ if (k->name_type == NULL)
+ return;
+
+ len = strlen("SSH_AUTH_EXT_NAME_TYPE=");
+ len += strlen(k->name_type) + 1;
+ s = xmalloc(len);
+ snprintf(s, len, "SSH_AUTH_EXT_NAME_TYPE=%s", k->name_type);
+
+ new_env = xmalloc(sizeof(struct envstring));
+ new_env->s = s;
+ new_env->next = custom_environment;
+ custom_environment = new_env;
+
+ return;
+}
+
/*
- * return 1 if access is granted, 0 if not.
+ * return 1 if access is granted, 0 if not, -1 if access explicitly denied
* side effect: sets key option flags
*/
int
@@ -72,6 +107,12 @@
return 1;
while (*opts && *opts != ' ' && *opts != '\t') {
+ cp = "deny-access";
+ if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ log("Authentication successful, but authorization denied");
+ packet_send_debug("Permission denied");
+ return -1;
+ }
cp = "no-port-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
********************************************************************************
Index: 2_9_p2_w_gss_and_krb5.4/sshd.8
--- 2_9_p2_w_gss_and_krb5.4/sshd.8 Tue, 26 Jun 2001 16:27:13 -0400 willian (OpenSSH/h/28_sshd.8 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/sshd.8 Tue, 03 Jul 2001 14:20:01 -0400 willian (OpenSSH/h/28_sshd.8 1.3 644)
@@ -871,7 +871,8 @@
.Pa $HOME/.ssh/authorized_keys2
file lists the DSA and RSA keys that are
permitted for public key authentication (PubkeyAuthentication)
-in protocol version 2.
+in protocol version 2. It can also list key names or key patterns
+for external authentication systems, such as krb4, krb5, gsi, etc...
.Pp
Each line of the file contains one
key (empty lines and lines starting with a
@@ -892,7 +893,19 @@
For protocol version 2 the keytype is
.Dq ssh-dss
or
-.Dq ssh-rsa .
+.Dq ssh-rsa
+or
+.Dq ssh-ext-named:<keytype>
+or
+.Dq ssh-ext-name-pat:<keytype> .
+.Pp
+Named keys and key name patterns follow the latter two, in double
+quotes if they contain whitespace. Named key types may include:
+.Dq krb4 ,
+.Dq krb5
+and/or
+.Dq gsi ,
+depending on what features are compiled in to OpenSSH.
.Pp
Note that lines in this file are usually several hundred bytes long
(because of the size of the RSA key modulus).
@@ -949,6 +962,10 @@
Environment variables set this way
override other default environment values.
Multiple options of this type are permitted.
+.It Cm deny-access
+This option ends authorized_keys2 processing if the key matches. This
+option is only really useful with named key and named key pattern
+entries.
.It Cm no-port-forwarding
Forbids TCP/IP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
Index: 2_9_p2_w_gss_and_krb5.4/key.h
--- 2_9_p2_w_gss_and_krb5.4/key.h Tue, 26 Jun 2001 16:27:13 -0400 willian (OpenSSH/j/7_key.h 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/key.h Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/j/7_key.h 1.4 644)
@@ -35,7 +35,9 @@
KEY_RSA,
KEY_DSA,
KEY_NULL,
- KEY_UNSPEC
+ KEY_UNSPEC,
+ KEY_NAME,
+ KEY_NAME_PAT
};
enum fp_type {
SSH_FP_SHA1,
@@ -49,12 +51,16 @@
int type;
RSA *rsa;
DSA *dsa;
+ u_char *name;
+ u_int name_len;
+ char *name_type;
};
Key *key_new(int type);
Key *key_new_private(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
+int key_match(Key *a, Key *b);
char *key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
Index: 2_9_p2_w_gss_and_krb5.4/key.c
--- 2_9_p2_w_gss_and_krb5.4/key.c Tue, 26 Jun 2001 16:27:13 -0400 willian (OpenSSH/j/8_key.c 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/key.c Tue, 03 Jul 2001 14:23:39 -0400 willian (OpenSSH/j/8_key.c 1.6 644)
@@ -56,6 +56,9 @@
k->type = type;
k->dsa = NULL;
k->rsa = NULL;
+ k->name = NULL;
+ k->name_len = 0;
+ k->name_type = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -72,6 +75,8 @@
dsa->pub_key = BN_new();
k->dsa = dsa;
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
case KEY_UNSPEC:
break;
default:
@@ -119,6 +124,14 @@
DSA_free(k->dsa);
k->dsa = NULL;
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
+ if (k->name != NULL)
+ xfree(k->name);
+ k->name_len = 0;
+ if (k->name_type != NULL)
+ xfree(k->name_type);
+ break;
case KEY_UNSPEC:
break;
default:
@@ -130,8 +143,9 @@
int
key_equal(Key *a, Key *b)
{
- if (a == NULL || b == NULL || a->type != b->type)
+ if (a == NULL || b == NULL || a->type != b->type) {
return 0;
+ }
switch (a->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -146,12 +160,67 @@
BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
break;
+ case KEY_NAME:
+ if ((a->name_type == NULL && b->name_type == NULL) ||
+ (a->name_type == b->name_type))
+ return (a->name_len == b->name_len) &&
+ (memcmp(a->name, b->name, a->name_len) == 0);
+ if (a->name_type == NULL || b->name_type == NULL)
+ return 0;
+ if (strcmp(a->name_type, b->name_type) == 0)
+ return (a->name_len == b->name_len) &&
+ (memcmp(a->name, b->name, a->name_len) == 0);
+ break;
+ case KEY_NAME_PAT:
+ return 0;
+ break;
default:
fatal("key_equal: bad key type %d", a->type);
break;
}
return 0;
}
+int
+key_match(Key *a, Key *b)
+{
+ debug3("key_match: trying to match %x and %x", a, b);
+ if (a == NULL || b == NULL)
+ return 0;
+
+ debug3("key_match: trying to match key types %d and %d -- KEY_NAME_PAT == %d", a->type, b->type, KEY_NAME_PAT);
+ /* One key must be a name pattern, the other must be a name */
+ if (!(a->type == KEY_NAME_PAT && b->type == KEY_NAME) &&
+ !(b->type == KEY_NAME_PAT && a->type == KEY_NAME))
+ return 0;
+
+ /* Both keys must have name types, or both must not */
+ /* or one key must have '*' as its name type */
+ if ((a->name_type == NULL && b->name_type != NULL) ||
+ (b->name_type == NULL && a->name_type != NULL)) {
+
+ debug3("key_match: foo");
+ if (a->name_type != NULL && *(a->name_type) != '*')
+ return 0;
+ if (b->name_type != NULL && *(b->name_type) != '*')
+ return 0;
+ }
+
+ /* Name type "*" matches any name type */
+ /* Otherwise name types must match */
+ if ((a->name_type != NULL && strcmp(a->name_type, b->name_type) != 0) &&
+ (*(a->name_type) != '*' || *(b->name_type) != '*')) {
+ debug3("key_match: a->name_type == %s", a->name_type ? a->name_type : "");
+ debug3("key_match: b->name_type == %s", b->name_type ? b->name_type : "");
+ return 0;
+ }
+
+ debug3("key_match: trying to match %s WITH %s", a->name, b->name);
+ if (a->type == KEY_NAME_PAT)
+ return match_pattern(b->name, a->name);
+ else
+ return match_pattern(a->name, b->name);
+}
+
u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
@@ -160,7 +229,7 @@
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
- int len = 0;
+ u_int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
@@ -363,11 +432,12 @@
{
Key *k;
int success = -1;
- char *cp, *space;
+ char *cp, *space, *name_type;
int len, n, type;
u_int bits;
- u_char *blob;
+ u_char *blob = NULL;
+ name_type = NULL;
cp = *cpp;
switch(ret->type) {
@@ -390,6 +460,8 @@
case KEY_UNSPEC:
case KEY_RSA:
case KEY_DSA:
+ case KEY_NAME:
+ case KEY_NAME_PAT:
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: no space");
@@ -397,6 +469,17 @@
}
*space = '\0';
type = key_type_from_name(cp);
+ if ((type == KEY_NAME) || (type == KEY_NAME_PAT)) {
+ char * colon = NULL;
+
+ colon = strchr(cp, ':');
+
+ debug3("key_read: handling named key or pattern (%d), %s, colon at %x", type, cp, colon);
+ if (colon != NULL && *(++colon) != '\0') {
+ name_type = xstrdup(colon);
+ } else
+ name_type == NULL;
+ }
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: no key found");
@@ -410,30 +493,80 @@
if (ret->type == KEY_UNSPEC) {
ret->type = type;
} else if (ret->type != type) {
- /* is a key, but different type */
- debug3("key_read: type mismatch");
- return 0;
+ if (! ((ret->type == KEY_NAME) &&
+ type == KEY_NAME_PAT)) {
+ /* is a key, but different type */
+ debug3("key_read: type mismatch");
+ return 0;
+ }
+ ret->type = type;
}
- len = 2*strlen(cp);
- blob = xmalloc(len);
- n = uudecode(cp, blob, len);
- if (n < 0) {
- error("key_read: uudecode %s failed", cp);
- return -1;
+ debug3("key_read: here -- ret->type == %d", ret->type);
+ if ((ret->type == KEY_NAME) || (ret->type == KEY_NAME_PAT)) {
+ char *quote, *newline;
+ debug3("key_read: reading named key %s", cp);
+ if (cp == NULL || *cp == '\0')
+ return 0;
+ if (*cp == '"') {
+ quote = strchr(++cp, '"');
+ if (quote == NULL) {
+ debug3("key_read: missing quote");
+ return 0;
+ }
+ *quote = '\0';
+ }
+ newline = strchr(cp, '\n');
+ if (newline != NULL)
+ *newline = '\0';
+ debug3("key_read: reading named key %s", cp);
+ k = key_new(ret->type);
+ k->name = (unsigned char *) xstrdup(cp);
+ k->name_len = strlen(cp);
+ k->name_type = name_type;
+ if (newline !=NULL)
+ *newline = '\n';
+ if (quote !=NULL)
+ *quote = '"';
+ debug3("key_read: read named key %s", k->name_type);
+ } else {
+ len = 2*strlen(cp);
+ blob = xmalloc(len);
+ n = uudecode(cp, blob, len);
+ if (n < 0) {
+ error("key_read: uudecode %s failed", cp);
+ return -1;
+ }
+ debug3("key_read: reading uuencoded key %s", blob);
+ k = key_from_blob(blob, n);
}
- k = key_from_blob(blob, n);
if (k == NULL) {
error("key_read: key_from_blob %s failed", cp);
return -1;
}
- xfree(blob);
+ if (blob != NULL)
+ xfree(blob);
if (k->type != type) {
- error("key_read: type mismatch: encoding error");
- key_free(k);
- return -1;
+ if (! ((ret->type == KEY_NAME) &&
+ type == KEY_NAME_PAT)) {
+ error("key_read: type mismatch: encoding error");
+ key_free(k);
+ return -1;
+ }
}
/*XXXX*/
- if (ret->type == KEY_RSA) {
+ if ((ret->type == KEY_NAME) || (ret->type == KEY_NAME_PAT)) {
+ /*
+ if (ret->name != NULL)
+ xfree(ret->name);
+ */
+ ret->name = k->name;
+ ret->name_len = k->name_len;
+ ret->name_type = k->name_type;
+ k->name = NULL;
+ k->name_type = NULL;
+ k->name_len = 0;
+ success = 1;
+ } else if (ret->type == KEY_RSA) {
if (ret->rsa != NULL)
RSA_free(ret->rsa);
ret->rsa = k->rsa;
@@ -487,7 +620,7 @@
}
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
- int len, n;
+ u_int len, n;
u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
@@ -498,6 +631,14 @@
}
xfree(blob);
xfree(uu);
+ } else if (key->type == KEY_NAME && key->name != NULL &&
+ key->name_len) {
+
+ fprintf(f, "%s ", key_ssh_name(key));
+ if (key->name_type != NULL)
+ fprintf(f, ":%s", key->name_type);
+ else
+ fprintf(f, " \"%.*s\"", key->name, key->name_len);
}
return success;
}
@@ -514,6 +655,12 @@
case KEY_DSA:
return "DSA";
break;
+ case KEY_NAME:
+ return "Named";
+ break;
+ case KEY_NAME_PAT:
+ return "Name_Pattern";
+ break;
}
return "unknown";
}
@@ -527,6 +674,12 @@
case KEY_DSA:
return "ssh-dss";
break;
+ case KEY_NAME:
+ return "ssh-ext-named";
+ break;
+ case KEY_NAME_PAT:
+ return "ssh-ext-name-pat";
+ break;
}
return "ssh-unknown";
}
@@ -604,6 +757,16 @@
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
break;
+ case KEY_NAME:
+ case KEY_NAME_PAT:
+ n = key_new(k->type);
+ n->name_len = k->name_len;
+ n->name = xmalloc(k->name_len);
+ memcpy(n->name, k->name, n->name_len);
+ if (k->name_type) {
+ n->name_type = xstrdup(k->name_type);
+ }
+ break;
default:
fatal("key_from_private: unknown type %d", k->type);
break;
@@ -624,6 +787,14 @@
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
return KEY_DSA;
+ } else if (strcmp(name, "ssh-ext-named") == 0){
+ return KEY_NAME;
+ } else if (strncmp(name, "ssh-ext-named:", strlen("ssh-ext-named:")) == 0){
+ return KEY_NAME;
+ } else if (strcmp(name, "ssh-ext-name-pat") == 0){
+ return KEY_NAME_PAT;
+ } else if (strncmp(name, "ssh-ext-name-pat:", strlen("ssh-ext-name-pat:")) == 0){
+ return KEY_NAME_PAT;
} else if (strcmp(name, "null") == 0){
return KEY_NULL;
}
Index: 2_9_p2_w_gss_and_krb5.4/auth2.c
--- 2_9_p2_w_gss_and_krb5.4/auth2.c Tue, 26 Jun 2001 16:27:13 -0400 willian (OpenSSH/k/6_auth2.c 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/auth2.c Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/k/6_auth2.c 1.3 644)
@@ -514,7 +514,7 @@
buffer_dump(&b);
#endif
/* test for correct signature */
- if (user_key_allowed(authctxt->pw, key) &&
+ if (user_key_allowed(authctxt->pw, key) > 0 &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
@@ -531,7 +531,7 @@
* if a user is not allowed to login. is this an
* issue? -markus
*/
- if (user_key_allowed(authctxt->pw, key)) {
+ if (user_key_allowed(authctxt->pw, key) > 0) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
@@ -791,19 +791,36 @@
continue;
}
}
- if (key_equal(found, key) &&
- auth_parse_options(pw, options, file, linenum) == 1) {
- found_key = 1;
- debug("matching key found: file %s, line %ld",
- file, linenum);
+ if (key_equal(found, key)) {
+ found_key = auth_parse_options(pw, options, file, linenum);
+ if (found_key == 0)
+ continue;
+ break;
+ }
+ if (key_match(found, key)) {
+ found_key = auth_parse_options(pw, options, file, linenum);
+ if (found_key == 0)
+ continue;
+ /* Special treatment for key name patterns belongs here */
break;
}
}
+
+done:
restore_uid();
fclose(f);
key_free(found);
- if (!found_key)
+ if (found_key > 0) {
+ debug("matching key found: file %s, line %ld",
+ file, linenum);
+ auth_set_key_env(key);
+ }
+ if (found_key == 0)
debug2("key not found");
+ if (found_key < 0) {
+ debug("user_key_allowed: matching deny key found: "
+ "file %s, line %ld", file, linenum);
+ }
return found_key;
}
Index: 2_9_p2_w_gss_and_krb5.4/auth-rsa.c
--- 2_9_p2_w_gss_and_krb5.4/auth-rsa.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/15_auth-rsa.c 1.1 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/auth-rsa.c Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/k/15_auth-rsa.c 1.2 644)
@@ -259,7 +259,7 @@
* If our options do not allow this key to be used,
* do not send challenge.
*/
- if (!auth_parse_options(pw, options, file, linenum))
+ if (auth_parse_options(pw, options, file, linenum) < 1)
continue;
/* Perform the challenge-response dialog for this key. */
Index: 2_9_p2_w_gss_and_krb5.4/auth-options.h
--- 2_9_p2_w_gss_and_krb5.4/auth-options.h Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/21_auth-optio 1.1 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/auth-options.h Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/k/21_auth-optio 1.2 644)
@@ -16,6 +16,8 @@
#ifndef AUTH_OPTIONS_H
#define AUTH_OPTIONS_H
+#include "key.h"
+
/* Linked list of custom environment strings */
struct envstring {
struct envstring *next;
@@ -37,6 +39,9 @@
int
auth_parse_options(struct passwd *pw, char *options, char *file,
u_long linenum);
+
+void
+auth_set_key_env(Key *k);
/* reset options flags */
void auth_clear_options(void);
Index: 2_9_p2_w_gss_and_krb5.4/auth-options.c
--- 2_9_p2_w_gss_and_krb5.4/auth-options.c Thu, 03 May 2001 16:12:13 -0400 jd (OpenSSH/k/22_auth-optio 1.1 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/auth-options.c Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/k/22_auth-optio 1.2 644)
@@ -55,8 +55,43 @@
channel_clear_permitted_opens();
}
+void auth_set_key_env(Key *k)
+{
+ struct envstring *new_env;
+ char *s;
+ int len;
+
+ if (k->type != KEY_NAME)
+ return;
+
+ len = strlen("SSH_AUTH_EXT_NAME=");
+ len += k->name_len + 1;
+ s = xmalloc(len);
+ snprintf(s, len, "SSH_AUTH_EXT_NAME=%.*s", k->name_len, k->name);
+ debug3("auth_set_key_env: Adding to the environment: %.*s", len, s);
+ new_env = xmalloc(sizeof(struct envstring));
+ new_env->s = s;
+ new_env->next = custom_environment;
+ custom_environment = new_env;
+
+ if (k->name_type == NULL)
+ return;
+
+ len = strlen("SSH_AUTH_EXT_NAME_TYPE=");
+ len += strlen(k->name_type) + 1;
+ s = xmalloc(len);
+ snprintf(s, len, "SSH_AUTH_EXT_NAME_TYPE=%s", k->name_type);
+
+ new_env = xmalloc(sizeof(struct envstring));
+ new_env->s = s;
+ new_env->next = custom_environment;
+ custom_environment = new_env;
+
+ return;
+}
+
/*
- * return 1 if access is granted, 0 if not.
+ * return 1 if access is granted, 0 if not, -1 if access explicitly denied
* side effect: sets key option flags
*/
int
@@ -72,6 +107,12 @@
return 1;
while (*opts && *opts != ' ' && *opts != '\t') {
+ cp = "deny-access";
+ if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ log("Authentication successful, but authorization denied");
+ packet_send_debug("Permission denied");
+ return -1;
+ }
cp = "no-port-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
packet_send_debug("Port forwarding disabled.");
Index: 2_9_p2_w_gss_and_krb5.4/gss-serv.c
--- 2_9_p2_w_gss_and_krb5.4/gss-serv.c Tue, 26 Jun 2001 16:27:13 -0400 willian (OpenSSH/l/25_gss-serv.c 1.1 644)
+++ 2_9_p2_w_gss_krb5_named_keys.5/gss-serv.c Tue, 03 Jul 2001 13:14:57 -0400 willian (OpenSSH/l/25_gss-serv.c 1.4 644)
@@ -127,24 +127,38 @@
int
ssh_gssapi_krb5_userok(char *name) {
krb5_principal princ;
- int retval;
+ int retval, retval2;
+ Key k;
if (ssh_gssapi_krb5_init() == 0)
return 0;
+ k.type = KEY_NAME;
+ k.name = gssapi_client_name.value;
+ k.name_len = strlen(gssapi_client_name.value);
+ k.name_type = "krb5";
+
+ debug3("ssh_gssapi_krb5_userok:");
+ debug3("ssh_gssapi_krb5_userok: %s", k.name_type);
+
if ((retval=krb5_parse_name(krb_context, gssapi_client_name.value,
&princ))) {
log("krb5_parse_name(): %.100s",
krb5_get_err_text(krb_context,retval));
return 0;
}
+
+ retval2 = user_key_allowed(getpwnam(name), &k);
+ if (retval2 < 0)
+ return 0;
+
if (krb5_kuserok(krb_context, princ, name))
retval = 1;
else
retval = 0;
krb5_free_principal(krb_context, princ);
- return retval;
+ return retval | retval2;
}
/* Make sure that this is called _after_ we've setuid to the user */
Visit our website at http://www.ubswarburg.com
This message contains confidential information and is intended only
for the individual named. If you are not the named addressee you
should not disseminate, distribute or copy this e-mail. Please
notify the sender immediately by e-mail if you have received this
e-mail by mistake and delete this e-mail from your system.
E-mail transmission cannot be guaranteed to be secure or error-free
as information could be intercepted, corrupted, lost, destroyed,
arrive late or incomplete, or contain viruses. The sender therefore
does not accept liability for any errors or omissions in the contents
of this message which arise as a result of e-mail transmission. If
verification is required please request a hard-copy version. This
message is provided for informational purposes and should not be
construed as a solicitation or offer to buy or sell any securities or
related financial instruments.
More information about the openssh-unix-dev
mailing list