Hello,
I need to allow for some people to execute ssh with one shared private
key for remote executing command on various machines. However, it is not
possible to set group permissions for private keys and it is possible
to have just one private key file for one user. Please, is it possible
to add patches into openssh development tree like these, so that standard
behavior of ssh is not changed, but when option GroupPrivateKey is used
with ssh, it is allowed to have group readable private key?
Thank you very much.
--- authfile.c.orig Thu Nov 27 15:01:01 2003
+++ authfile.c Thu Nov 27 16:50:39 2003
@@ -496,7 +496,7 @@
}
static int
-key_perm_ok(int fd, const char *filename)
+key_perm_ok(int fd, const char *filename, int group_private_key)
{
struct stat st;
@@ -510,7 +510,10 @@
#ifdef HAVE_CYGWIN
if (check_ntsec(filename))
#endif
- if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
+ if ((!group_private_key
+ && (st.st_uid == getuid()) && (st.st_mode & 077) != 0)
+ || (group_private_key && (st.st_uid == getuid()
+ || st.st_gid == getgid()) && (st.st_mode & 007) != 0)) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE!
@");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
@@ -525,14 +528,14 @@
Key *
key_load_private_type(int type, const char *filename, const char *passphrase,
- char **commentp)
+ char **commentp, int group_private_key)
{
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
- if (!key_perm_ok(fd, filename)) {
+ if (!key_perm_ok(fd, filename, group_private_key)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
@@ -558,7 +561,7 @@
Key *
key_load_private(const char *filename, const char *passphrase,
- char **commentp)
+ char **commentp, int group_private_key)
{
Key *pub, *prv;
int fd;
@@ -566,7 +569,7 @@
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
- if (!key_perm_ok(fd, filename)) {
+ if (!key_perm_ok(fd, filename, group_private_key)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
--- authfile.h.orig Thu Nov 27 16:28:31 2003
+++ authfile.h Thu Nov 27 16:28:42 2003
@@ -18,8 +18,8 @@
int key_save_private(Key *, const char *, const char *, const char *);
Key *key_load_public(const char *, char **);
Key *key_load_public_type(int, const char *, char **);
-Key *key_load_private(const char *, const char *, char **);
-Key *key_load_private_type(int, const char *, const char *, char **);
+Key *key_load_private(const char *, const char *, char **, int);
+Key *key_load_private_type(int, const char *, const char *, char **, int);
Key *key_load_private_pem(int, int, const char *, char **);
#endif
--- readconf.c.orig Thu Nov 27 18:04:27 2003
+++ readconf.c Thu Nov 27 18:06:49 2003
@@ -105,7 +105,7 @@
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
- oDeprecated, oUnsupported
+ oGroupPrivateKey, oDeprecated, oUnsupported
} OpCodes;
/* Textual representations of the tokens. */
@@ -188,6 +188,7 @@
{ "rekeylimit", oRekeyLimit },
{ "connecttimeout", oConnectTimeout },
{ "addressfamily", oAddressFamily },
+ { "groupprivatekey", oGroupPrivateKey },
{ NULL, oBadOption }
};
@@ -732,6 +733,10 @@
intptr = &options->enable_ssh_keysign;
goto parse_flag;
+ case oGroupPrivateKey:
+ intptr = &options->group_private_key;
+ goto parse_flag;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -859,6 +864,7 @@
options->no_host_authentication_for_localhost = - 1;
options->rekey_limit = - 1;
options->verify_host_key_dns = -1;
+ options->group_private_key = -1;
}
/*
@@ -973,6 +979,8 @@
options->rekey_limit = 0;
if (options->verify_host_key_dns == -1)
options->verify_host_key_dns = 0;
+ if (options->group_private_key == -1)
+ options->group_private_key = 0;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
--- readconf.h.orig Thu Nov 27 15:19:30 2003
+++ readconf.h Thu Nov 27 15:20:11 2003
@@ -87,6 +87,7 @@
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
Key *identity_keys[SSH_MAX_IDENTITY_FILES];
+ int group_private_key;
/* Local TCP/IP forward requests. */
int num_local_forwards;
--- ssh.c.orig Thu Nov 27 16:31:08 2003
+++ ssh.c Thu Nov 27 16:30:46 2003
@@ -634,11 +634,13 @@
PRIV_START;
sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
- _PATH_HOST_KEY_FILE, "", NULL);
+ _PATH_HOST_KEY_FILE, "", NULL, options.group_private_key);
sensitive_data.keys[1] = key_load_private_type(KEY_DSA,
- _PATH_HOST_DSA_KEY_FILE, "", NULL);
+ _PATH_HOST_DSA_KEY_FILE, "", NULL,
+ options.group_private_key);
sensitive_data.keys[2] = key_load_private_type(KEY_RSA,
- _PATH_HOST_RSA_KEY_FILE, "", NULL);
+ _PATH_HOST_RSA_KEY_FILE, "", NULL,
+ options.group_private_key);
PRIV_END;
if (options.hostbased_authentication == 1 &&
--- ssh_config.5.orig Thu Nov 27 17:40:32 2003
+++ ssh_config.5 Thu Nov 27 18:03:02 2003
@@ -349,6 +349,15 @@
Specifies a file to use for the global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts .
+.It Cm GroupPrivateKey
+If this flag is set to
+.Dq yes ,
+ssh will allow to have private key file with group permissions set.
+If the option is set to
+.Dq no ,
+only user is allowed to own the private key file.
+The default is
+.Dq no .
.It Cm GSSAPIAuthentication
Specifies whether authentication based on GSSAPI may be used, either using
the result of a successful key exchange, or using GSSAPI user
--- sshconnect1.c.orig Thu Nov 27 16:31:20 2003
+++ sshconnect1.c Thu Nov 27 16:32:05 2003
@@ -243,7 +243,8 @@
if (public->flags & KEY_FLAG_EXT)
private = public;
else
- private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
+ private = key_load_private_type(KEY_RSA1, authfile, "", NULL,
+ options.group_private_key);
if (private == NULL && !options.batch_mode) {
snprintf(buf, sizeof(buf),
"Enter passphrase for RSA key '%.100s': ", comment);
@@ -251,7 +252,8 @@
passphrase = read_passphrase(buf, 0);
if (strcmp(passphrase, "") != 0) {
private = key_load_private_type(KEY_RSA1,
- authfile, passphrase, NULL);
+ authfile, passphrase, NULL,
+ options.group_private_key);
quit = 0;
} else {
debug2("no passphrase given, try next key");
--- sshconnect2.c.orig Thu Nov 27 16:31:25 2003
+++ sshconnect2.c Thu Nov 27 16:36:38 2003
@@ -967,7 +967,8 @@
debug3("no such identity: %s", filename);
return NULL;
}
- private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
+ private = key_load_private_type(KEY_UNSPEC, filename, "", NULL,
+ options.group_private_key);
if (private == NULL) {
if (options.batch_mode)
return NULL;
@@ -977,7 +978,8 @@
passphrase = read_passphrase(prompt, 0);
if (strcmp(passphrase, "") != 0) {
private = key_load_private_type(KEY_UNSPEC, filename,
- passphrase, NULL);
+ passphrase, NULL,
+ options.group_private_key);
quit = 0;
} else {
debug2("no passphrase given, try next key");
--- sshd.c.orig Thu Nov 27 16:33:07 2003
+++ sshd.c Thu Nov 27 16:35:19 2003
@@ -966,7 +966,7 @@
sensitive_data.have_ssh2_key = 0;
for (i = 0; i < options.num_host_key_files; i++) {
- key = key_load_private(options.host_key_files[i], "", NULL);
+ key = key_load_private(options.host_key_files[i], "", NULL, 0);
sensitive_data.host_keys[i] = key;
if (key == NULL) {
error("Could not load host key: %s",
--- ssh-add.c.orig Thu Nov 27 18:14:33 2003
+++ ssh-add.c Thu Nov 27 18:15:04 2003
@@ -142,12 +142,12 @@
return -1;
}
/* At first, try empty passphrase */
- private = key_load_private(filename, "", &comment);
+ private = key_load_private(filename, "", &comment, 0);
if (comment == NULL)
comment = xstrdup(filename);
/* try last */
if (private == NULL && pass != NULL)
- private = key_load_private(filename, pass, NULL);
+ private = key_load_private(filename, pass, NULL, 0);
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
@@ -160,7 +160,8 @@
xfree(comment);
return -1;
}
- private = key_load_private(filename, pass, &comment);
+ private = key_load_private(filename, pass,
+ &comment, 0);
if (private != NULL)
break;
clear_pass();
--- ssh-keygen.c.orig Thu Nov 27 18:15:47 2003
+++ ssh-keygen.c Thu Nov 27 18:16:19 2003
@@ -127,14 +127,14 @@
char *pass;
Key *prv;
- prv = key_load_private(filename, "", NULL);
+ prv = key_load_private(filename, "", NULL, 0);
if (prv == NULL) {
if (identity_passphrase)
pass = xstrdup(identity_passphrase);
else
pass = read_passphrase("Enter passphrase: ",
RP_ALLOW_STDIN);
- prv = key_load_private(filename, pass, NULL);
+ prv = key_load_private(filename, pass, NULL, 0);
memset(pass, 0, strlen(pass));
xfree(pass);
}
@@ -560,7 +560,7 @@
exit(1);
}
/* Try to load the file with empty passphrase. */
- private = key_load_private(identity_file, "", &comment);
+ private = key_load_private(identity_file, "", &comment, 0);
if (private == NULL) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
@@ -569,7 +569,7 @@
read_passphrase("Enter old passphrase: ",
RP_ALLOW_STDIN);
private = key_load_private(identity_file, old_passphrase,
- &comment);
+ &comment, 0);
memset(old_passphrase, 0, strlen(old_passphrase));
xfree(old_passphrase);
if (private == NULL) {
@@ -672,7 +672,7 @@
perror(identity_file);
exit(1);
}
- private = key_load_private(identity_file, "", &comment);
+ private = key_load_private(identity_file, "", &comment, 0);
if (private == NULL) {
if (identity_passphrase)
passphrase = xstrdup(identity_passphrase);
@@ -682,7 +682,8 @@
passphrase = read_passphrase("Enter passphrase: ",
RP_ALLOW_STDIN);
/* Try to load using the passphrase. */
- private = key_load_private(identity_file, passphrase, &comment);
+ private = key_load_private(identity_file, passphrase,
+ &comment, 0);
if (private == NULL) {
memset(passphrase, 0, strlen(passphrase));
xfree(passphrase);
--
Rudolf Cejka <cejkar at fit.vutbr.cz> http://www.fit.vutbr.cz/~cejkar
Brno University of Technology, Faculty of Information Technology
Bozetechova 2, 612 66 Brno, Czech Republic