Please find attached a patch against openssh-4.7p1 It extends the Match in sshd_config. The point is that it is sometimes easier (and more secure) to match on NOT something. A criterium may be preceded by ! which inverts the condition, thus: Match !Group sysadmins ForceCommand /usr/bin/sftp forces use of sftp on any user who is not a system administrator. A !! has the same effect as no ! - but I didn't document that. I am looking at sftp, extend it: * read a config file - optionally * commands to restrict a user to their $HOME. -- Alain Williams Linux Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer. +44 (0) 787 668 0256 http://www.phcomp.co.uk/ Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php Chairman of UKUUG: http://www.ukuug.org/ #include <std_disclaimer.h> -------------- next part -------------- --- servconf.c.orig 2007-05-20 06:03:16.000000000 +0100 +++ servconf.c 2007-11-11 17:21:38.000000000 +0000 @@ -498,13 +498,21 @@ * PermittedChannelRequests session,forwarded-tcpip */ +/* Check if user is in the comma separated group list grps. Invert condition if not. + * line is the config file line. + * Return: + * 1 match + * 0 not match + * -1 error + */ static int -match_cfg_line_group(const char *grps, int line, const char *user) +match_cfg_line_group(const char *grps, int line, const char *user, int not) { int result = 0; u_int ngrps = 0; char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS]; struct passwd *pw; + char* notstr = not ? "!" : ""; /* * Even if we do not have a user yet, we still need to check for @@ -529,12 +537,12 @@ } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { debug("Can't Match group because user %.100s not in any group " "at line %d", user, line); - } else if (ga_match(grplist, ngrps) != 1) { - debug("user %.100s does not match group %.100s at line %d", - user, arg, line); + } else if (ga_match(grplist, ngrps) == not) { + debug("user %.100s does not match %sgroup %.100s at line %d", + user, notstr, arg, line); } else { - debug("user %.100s matched group %.100s at line %d", user, - arg, line); + debug("user %.100s matched %sgroup %.100s at line %d", user, + notstr, arg, line); result = 1; } out: @@ -550,6 +558,8 @@ int result = 1; char *arg, *attrib, *cp = *condition; size_t len; + int not = 0; + char* notstr; if (user == NULL) debug3("checking syntax for 'Match %s'", cp); @@ -559,6 +569,13 @@ address ? address : "(null)"); while ((attrib = strdelim(&cp)) && *attrib != '\0') { + while(*attrib == '!') { /* Parse a '!' to mean invert the condition */ + not ^= 1; + attrib++; + } + if(*attrib == '\0') /* Maybe a ! was followed by white space */ + continue; + notstr = not ? "!" : ""; /* For debug */ if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { error("Missing Match criteria for %s", attrib); return -1; @@ -567,15 +584,16 @@ if (strcasecmp(attrib, "user") == 0) { if (!user) { result = 0; + not = 0; continue; } - if (match_pattern_list(user, arg, len, 0) != 1) + if (match_pattern_list(user, arg, len, 0) == not) result = 0; else - debug("user %.100s matched 'User %.100s' at " - "line %d", user, arg, line); + debug("user %.100s matched '%sUser %.100s' at " + "line %d", user, notstr, arg, line); } else if (strcasecmp(attrib, "group") == 0) { - switch (match_cfg_line_group(arg, line, user)) { + switch (match_cfg_line_group(arg, line, user, not)) { case -1: return -1; case 0: @@ -584,27 +602,30 @@ } else if (strcasecmp(attrib, "host") == 0) { if (!host) { result = 0; + not = 0; continue; } - if (match_hostname(host, arg, len) != 1) + if (match_hostname(host, arg, len) == not) result = 0; else - debug("connection from %.100s matched 'Host " - "%.100s' at line %d", host, arg, line); + debug("connection from %.100s matched '%sHost " + "%.100s' at line %d", host, notstr, arg, line); } else if (strcasecmp(attrib, "address") == 0) { if (!address) { result = 0; + not = 0; continue; } - if (match_hostname(address, arg, len) != 1) + if (match_hostname(address, arg, len) == not) result = 0; else - debug("connection from %.100s matched 'Address " - "%.100s' at line %d", address, arg, line); + debug("connection from %.100s matched '%sAddress " + "%.100s' at line %d", address, notstr, arg, line); } else { error("Unsupported Match attribute %s", attrib); return -1; } + not = 0; /* Reset for next condition */ } if (user != NULL) debug3("match %sfound", result ? "" : "not "); --- sshd_config.5.orig 2007-06-11 05:07:13.000000000 +0100 +++ sshd_config.5 2007-11-11 17:17:16.000000000 +0000 @@ -529,6 +529,16 @@ .Cm X11Forwarding , and .Cm X11UseLocalHost . +.Pp +A criterium may be preceded by +.Cm ! +which inverts the condition, thus: +.pP +.Bl -tag -width Ds -compact -offset indent +.It Match !Group sysadmins +.It ForceCommand /usr/bin/sftp +.El +forces use of sftp on any user who is not a system administrator. .It Cm MaxAuthTries Specifies the maximum number of authentication attempts permitted per connection.