Raymond M. Reskusich
2002-Mar-28 16:59 UTC
[PATCH] Feature addition: user access control per auth method
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];
Frank Cusack
2002-Mar-28 19:13 UTC
[PATCH] Feature addition: user access control per auth method
On Thu, Mar 28, 2002 at 10:59:49AM -0600, Raymond M. Reskusich wrote:> 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[...] IMHO, this is better done with the PAMAcctService proposal from a week ago. Of course, yours is better in that there's actual code. :-) /fc