[PATCH] Feature addition: user access control per auth method

Raymond M. Reskusich reskusic at uiuc.edu
Fri Mar 29 03:59:49 EST 2002


I added a few features to openssh for my local use that I think would
be more broadly useful.  I basically added access control lists to
control who would be allowed public key authentication.  I added four
config file entries for the server:            

PubkeyAllowUsers
PubkeyDenyUsers
PubkeyAllowGroups
PubkeyDenyGroups 

These follow the same sematics as the already existing entries for
allowing logins.  So far I have this implemented for SSH2 pubkey auth,
but I coded it to make adding corresponding entries for any auth
method easy.  I'd be happy to do so if this was desired. I'm not sure
if there is any interest this functionality, but I've been wanting it
for a while.  In particular, it's helpful to allow pubkey auth for
trusted users and trusted system, while not allowing the other 10000
users to make it into another .rhosts. 

Below I've attached a patch for this feature off of V_3_1_P1.  I'd
appreciate any feedback.

Raymond M. Reskusich
reskusic at uiuc.edu





Index: auth.c
===================================================================
RCS file: /cvs/openssh/auth.c,v
retrieving revision 1.45
diff -u -r1.45 auth.c
--- auth.c	5 Mar 2002 01:42:43 -0000	1.45
+++ auth.c	28 Mar 2002 16:44:29 -0000
@@ -197,6 +197,80 @@
 	return 1;
 }
 
+/*
+ * Check if the user is allowed to login with a given method.
+ * If the user is in DenyUsers or his group is in DenyGroups,
+ * return false.
+ * If AllowUsers is non-empty, and doesn't contain the user, return 
+ * false.
+ * If AllowGroups is non-empty, and doesn't contain the user's group
+ * return false.
+ * Otherwise, return true. 
+ */
+int auth_allowed_user(struct passwd *pw, Authaccess access)
+{
+	const char *hostname = NULL, *ipaddr = NULL;
+	int i;
+
+	if (!pw || !pw->pw_name)
+	   return 0;
+
+	if (access.num_deny_users > 0 || access.num_allow_users > 0) {
+	   hostname = get_canonical_hostname(options.verify_reverse_mapping);
+	   ipaddr = get_remote_ipaddr();
+	}
+
+	/* Return false if user is listed in DenyUsers */
+	if (access.num_deny_users > 0) {
+		for (i = 0; i < access.num_deny_users; i++)
+			if (match_user(pw->pw_name, hostname, ipaddr,
+			    access.deny_users[i]))
+				return 0;
+	}				
+	
+	/* Return false if AllowUsers is non-empty, and user is not listed */
+	if (access.num_allow_users > 0) {
+	        for (i = 0; i < access.num_allow_users; i++)
+		        if (match_user(pw->pw_name, hostname, ipaddr,
+			    access.allow_users[i]))
+			    break;
+		/* i < access.num_allow_users iff we break for loop */
+		if ( i >= access.num_allow_users)
+			return 0;
+	}
+
+	if (access.num_allow_groups > 0 || access.num_deny_groups > 0) {
+	        /* load up the user's group list */
+		if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+			return 0;
+			
+		/* return false if the user is in a denied group */
+		if (access.num_deny_groups > 0)
+			if (ga_match(access.deny_groups,
+			   access.num_deny_groups)) {
+				ga_free();
+				return 0;
+			}
+
+		/* 
+		 *  Return false if the allowed groups are specified and the 
+                 *  user is not in one 
+		 */
+		if (access.num_allow_groups > 0)
+			if (!ga_match(access.allow_groups,
+			    access.num_allow_groups)) {
+				ga_free();
+				return 0;
+			}
+
+		ga_free();
+	}
+
+	/* We have no reason to deny the user authentication */
+	return 1;
+
+}
+
 Authctxt *
 authctxt_new(void)
 {
Index: auth.h
===================================================================
RCS file: /cvs/openssh/auth.h,v
retrieving revision 1.30
diff -u -r1.30 auth.h
--- auth.h	5 Mar 2002 01:53:04 -0000	1.30
+++ auth.h	28 Mar 2002 16:44:29 -0000
@@ -43,6 +43,7 @@
 #endif
 
 typedef struct Authctxt Authctxt;
+typedef struct Authaccess Authaccess;
 typedef struct KbdintDevice KbdintDevice;
 
 struct Authctxt {
@@ -71,6 +72,19 @@
 #endif
 };
 
+/* holds the access lists for a given auth method */
+struct Authaccess {
+       int		num_allow_users;
+       char	      **allow_users;
+       int		num_deny_users;
+       char	      **deny_users;
+       int	        num_allow_groups;
+       char	      **allow_groups;
+       int	        num_deny_groups;
+       char	      **deny_groups;
+};
+
+
 /*
  * Keyboard interactive device:
  * init_ctx	returns: non NULL upon success
@@ -133,6 +147,7 @@
 void	auth2_challenge_stop(Authctxt *);
 
 int	allowed_user(struct passwd *);
+int	auth_allowed_user(struct passwd *, Authaccess);
 
 char	*get_challenge(Authctxt *);
 int	verify_response(Authctxt *, const char *);
Index: auth2.c
===================================================================
RCS file: /cvs/openssh/auth2.c,v
retrieving revision 1.91
diff -u -r1.91 auth2.c
--- auth2.c	26 Feb 2002 18:09:43 -0000	1.91
+++ auth2.c	28 Mar 2002 16:44:29 -0000
@@ -51,6 +51,7 @@
 #include "hostfile.h"
 #include "canohost.h"
 #include "match.h"
+#include "groupaccess.h"
 
 /* import */
 extern ServerOptions options;
@@ -85,6 +86,7 @@
 static int userauth_pubkey(Authctxt *);
 static int userauth_hostbased(Authctxt *);
 static int userauth_kbdint(Authctxt *);
+static int pubkey_allowed_user(struct passwd *);
 
 Authmethod authmethods[] = {
 	{"none",
@@ -408,6 +410,13 @@
 		debug2("userauth_pubkey: disabled because of invalid user");
 		return 0;
 	}
+
+	/* check to see if the user is allowed to use pubkey authentication */
+	if (!pubkey_allowed_user(authctxt->pw)) {
+		debug2("userauth_pubkey: user not allowed pubkey auth");
+		return 0;
+	}
+	
 	have_sig = packet_get_char();
 	if (datafellows & SSH_BUG_PKAUTH) {
 		debug2("userauth_pubkey: SSH_BUG_PKAUTH");
@@ -796,3 +805,24 @@
 
 	return (host_status == HOST_OK);
 }
+
+
+/*
+ * Check if the user is allowed to log in with public key authentication.
+ */
+static int pubkey_allowed_user(struct passwd *pw)
+{
+	Authaccess access;
+
+	access.num_allow_users = options.num_pkey_allow_users;
+	access.allow_users = options.pkey_allow_users;
+	access.num_deny_users = options.num_pkey_deny_users;
+	access.deny_users = options.pkey_deny_users;
+	access.num_allow_groups = options.num_pkey_allow_groups;
+	access.allow_groups = options.pkey_allow_groups;
+	access.num_deny_groups = options.num_pkey_deny_groups;
+	access.deny_groups = options.pkey_deny_groups;
+
+	return auth_allowed_user(pw, access);
+}
+
Index: servconf.c
===================================================================
RCS file: /cvs/openssh/servconf.c,v
retrieving revision 1.77
diff -u -r1.77 servconf.c
--- servconf.c	5 Feb 2002 01:26:35 -0000	1.77
+++ servconf.c	28 Mar 2002 16:44:29 -0000
@@ -96,6 +96,10 @@
 	options->num_deny_users = 0;
 	options->num_allow_groups = 0;
 	options->num_deny_groups = 0;
+	options->num_pkey_allow_users = 0;
+	options->num_pkey_deny_users = 0;
+	options->num_pkey_allow_groups = 0;
+	options->num_pkey_deny_groups = 0;
 	options->ciphers = NULL;
 	options->macs = NULL;
 	options->protocol = SSH_PROTO_UNKNOWN;
@@ -267,7 +271,8 @@
 	sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
-	sDeprecated
+	sDeprecated, sPubkeyAllowUsers, sPubkeyDenyUsers,
+	sPubkeyAllowGroups, sPubkeyDenyGroups
 } ServerOpCodes;
 
 /* Textual representation of the tokens. */
@@ -342,6 +347,10 @@
 	{ "clientalivecountmax", sClientAliveCountMax },
 	{ "authorizedkeysfile", sAuthorizedKeysFile },
 	{ "authorizedkeysfile2", sAuthorizedKeysFile2 },
+	{ "pubkeyallowusers", sPubkeyAllowUsers },
+	{ "pubkeydenyusers", sPubkeyDenyUsers },
+	{ "pubkeyallowgroups", sPubkeyAllowGroups },
+	{ "pubkeydenygroups", sPubkeyDenyGroups },
 	{ NULL, sBadOption }
 };
 
@@ -751,6 +760,43 @@
 				fatal("%s line %d: too many deny groups.",
 				    filename, linenum);
 			options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
+		}
+		break;
+		
+		
+	case sPubkeyAllowUsers:
+		while ((arg = strdelim(&cp)) && *arg != '\0') {
+		      if (options->num_pkey_allow_users >= MAX_ALLOW_USERS)
+				fatal("%s line %d: too many public key allow users.",
+				   filename, linenum);
+			options->pkey_allow_users[options->num_pkey_allow_users++] = xstrdup(arg);
+		}
+		break;
+
+	case sPubkeyDenyUsers:
+		while ((arg = strdelim(&cp)) && *arg != '\0') {
+			if (options->num_pkey_deny_users >= MAX_DENY_USERS)
+				fatal( "%s line %d: too many public key deny users.",
+				   filename, linenum);
+			options->pkey_deny_users[options->num_pkey_deny_users++] = xstrdup(arg);
+		}
+		break;
+
+	case sPubkeyAllowGroups:
+		while ((arg = strdelim(&cp)) && *arg != '\0') {
+			if (options->num_pkey_allow_groups >= MAX_ALLOW_GROUPS)
+				fatal("%s line %d: too many public key allow groups.",
+				   filename, linenum);
+			options->pkey_allow_groups[options->num_pkey_allow_groups++] = xstrdup(arg);
+		}
+		break;
+
+	case sPubkeyDenyGroups:
+		while ((arg = strdelim(&cp)) && *arg != '\0') {
+			if (options->num_pkey_deny_groups >= MAX_DENY_GROUPS)
+				fatal("%s line %d: too many public key deny groups.",
+				   filename, linenum);
+			options->pkey_deny_groups[options->num_pkey_deny_groups++] = xstrdup(arg);
 		}
 		break;
 
Index: servconf.h
===================================================================
RCS file: /cvs/openssh/servconf.h,v
retrieving revision 1.45
diff -u -r1.45 servconf.h
--- servconf.h	5 Mar 2002 01:53:05 -0000	1.45
+++ servconf.h	28 Mar 2002 16:44:29 -0000
@@ -107,6 +107,14 @@
 	char   *allow_groups[MAX_ALLOW_GROUPS];
 	u_int num_deny_groups;
 	char   *deny_groups[MAX_DENY_GROUPS];
+	u_int num_pkey_allow_users;
+        char   *pkey_allow_users[MAX_ALLOW_USERS];
+	u_int num_pkey_deny_users;
+	char   *pkey_deny_users[MAX_DENY_USERS];
+	u_int num_pkey_allow_groups;
+	char   *pkey_allow_groups[MAX_ALLOW_GROUPS];
+	u_int num_pkey_deny_groups;
+	char   *pkey_deny_groups[MAX_DENY_GROUPS];
 
 	u_int num_subsystems;
 	char   *subsystem_name[MAX_SUBSYSTEMS];



More information about the openssh-unix-dev mailing list