Visit Jeremy's Blog.
Go Back > Forums > Linux Forums > Linux - Software
User Name
Linux - Software This forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.


  Search this Thread
Old 07-28-2011, 05:35 PM   #1
Registered: Apr 2008
Location: Cleveland, Ohio
Distribution: SuSE, CentOS, Fedora, Ubuntu
Posts: 106

Rep: Reputation: 23
Linux authentication with LDAP - select user's shell based on group membership

Hello, I'm supposed to set up LDAP authentication on over 200 linux servers, and I'd like to select the shell assigned to the user based on their group membership. For example, someone in the "Help Desk" group should get the /usr/local/bin/menu shell, while someone in the "Shop Systems" group should get the normal /bin/bash shell, and someone not in either group would have no login.

I could probably write a custom shell to do this, but I was wondering if there were any way to specify this using winbind?

Old 07-28-2011, 07:28 PM   #2
Registered: Apr 2002
Location: in a fallen world
Distribution: slackware by choice, others too :} ... android.
Posts: 23,067
Blog Entries: 11

Rep: Reputation: 911Reputation: 911Reputation: 911Reputation: 911Reputation: 911Reputation: 911Reputation: 911Reputation: 911
I'm not aware of any schema extensions that tie loginshells to
netgroups; I'd write a perl-script and set the shell for the
individuals based on their group memberships. May have interesting
results if someone is part of several groups - you'd have to
make sure you process the groups in whatever order you see fit.

Old 07-29-2011, 01:54 AM   #3
Nominal Animal
Senior Member
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947Reputation: 947
I've used the opposite approach to Tinkster on some servers: use Bash as the shell for all users, and modify /etc/bashrc to exec another shell if the user belongs to a specific group.

Because the exec'd program will replace the shell, there will be no extra processes lying around. It is a very clean and reliable solution. You can even allow SCP/SFTP connections at the same time, if you only do the exec for interactive/login shells. (Bash will only set PS1 if it is interactive. It will not be set if the user is using e.g. SCP or SFTP.)

You will need to edit /etc/shells, removing (or at least commenting out) all other shells. Otherwise users can just use the chsh command to change to some other shell. (Or, you can make sure your users cannot change the shell attribute in your centralized user database. It all depends on how you're set up.)

Since the common shell commands provide the groups the user belongs in as a string with spaces as separators, having spaces in the group names does cause problems. If you have groups named "Help Desk", "General Help", and "Desk Fixers", you cannot reliably check for "Help Desk" in the space separated list using the normal tools. For example, the list may contain "General Help Desk Fixers" but no "Help Desk"; this is not easy to resolve correctly.

To avoid all that mess, I wrote a little helper in C you could use:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>

/* Maximum number of group memberships. */
#define   MAX_GIDS   1024

gid_t     group[MAX_GIDS];
int       groups = 0;

int ismember(const char *const name)
	struct group    *gs;

	if (!name || !*name)
		return 0;

	gs = getgrnam(name);
	if (gs) {
		const gid_t	g = gs->gr_gid;
		int		i = groups;

		while (i-->0)
			if (group[i] == g)
				return 1;

	return 0;

int main(int argc, char *argv[])
	int	i;

	if (argc < 2 ||
	    (argv[1] && argv[1][0] == '-' && argv[1][1] == 'h' && !argv[1][2]) ||
	    (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' &&
	                argv[1][2] == 'h' && argv[1][3] == 'e' &&
	                argv[1][4] == 'l' && argv[1][5] == 'p' && !argv[1][6])) {
		fprintf(stderr, "\nUsage: %s [ -h | --help ]\n       %s groupname(s)...\n", argv[0], argv[0]);
		fprintf(stderr, "\nThis program will return success (exit status 0) if and only if\n"
		                "the current user is a member of all named groups.\n\n");
		return 3;

	/* Effective group ID is always checked. */
	group[0] = getegid();

	/* Supplemental group memberships. */
	i = getgroups(MAX_GIDS - 1, (gid_t *)&(group[1]));
	if (i == -1)
		return 2;
	groups = 1 + i;

	/* Check group names specified on the command line. */
	for (i = 1; i < argc; i++)
		if (!ismember(argv[i]))
			return 1;

	/* We are a member of all specified groups. */
	return 0;
If you save it as e.g. memberof.c, you can compile and install it as /usr/local/bin/memberof via
gcc -Wall -O3 -o memberof memberof.c
sudo install -m 0755 memberof /usr/local/bin/memberof
It is a very simple program you can use to check if the current user is a member of a group (or all specified groups). If I were you, I'd install it on all machines, then add
/usr/local/bin/memberof "Help Desk" && exec /usr/local/bin/menu
at the beginning of /etc/bashrc or /etc/bash.bashrc, depending on which one your distribution uses. One will always exist, since all Linux distributions install Bash; only the file name varies a bit.

If you do not want to use my program, you can rely on id (utility, /usr/bin/id), but do recall the issues with group names containing spaces. Based on the group name:
groups=" $(id -Gn) "
[ "${groups}" != "${groups/ Help Desk /}" ] && exec /usr/local/bin/menu
unset groups
Same but this time using the numeric group ID -- this avoids the issues with spaces, but maintenance is of course tedious:
groups=" $(id -G) "
# Group 2345 = Help Desk:  /usr/local/bin/menu
[ "${groups}" != "${groups/ 2345 /}" ] && exec /usr/local/bin/menu
unset groups
The above two generate a string with spaces around each group name or number, including the first and last ones. Then, Bash string manipulation is used to remove that one group from the list. If the list changes, then user is a member of that group, and the other program replaces the Bash shell. (My program first converts each group name to group ID number, then checks if the current user group list contains that ID. My program has no issues with any characters used in group names.)

Note that if a user is a member of multiple such groups, the shell they get to depends on the order of the checks you implement: first match wins. Personally, I'd start with the least privileged, so that accidentally adding group memberships will not bump a user to a different shell. (You need to remove the "lower" membership too, to bump up the user.)

Finally, /etc/shells and /etc/bashrc or /etc/bash.bashrc are of course local to each server you use. This allows you to specify different behaviours on different servers. Obviously you also need to keep the configuration in sync, if you want to have the same behaviour on different servers. Those files are fortunately "constant", same across all servers using the same distribution.

I hope you find this useful,

Last edited by Nominal Animal; 07-29-2011 at 02:00 AM. Reason: typos, and the final note.
Old 08-02-2011, 04:28 PM   #4
Registered: Apr 2008
Location: Cleveland, Ohio
Distribution: SuSE, CentOS, Fedora, Ubuntu
Posts: 106

Original Poster
Rep: Reputation: 23
Thanks Nominal! I will try out your program. That might do the trick.
Old 08-02-2011, 07:50 PM   #5
LQ Guru
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 9,078
Blog Entries: 4

Rep: Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165Reputation: 3165
/me nods... Yes, it seems to me that a little "trampoline" program ought to do the trick. This program would be launched, perhaps as a profile script at login. It would look for another shell program, and, if it finds one, switches to it. Perhaps, if it does not, the trampoline can drop into some kind of a default. As long as it is both trouble-free and seamless, you ought to be in good shape.


ldap, winbind

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
home directories based on group membership freakyal Linux - Server 8 07-13-2011 12:22 AM
[SOLVED] Apache authentication: allow LDAP group OR user named guest, but not all LDAP users AlucardZero Linux - Server 1 05-25-2011 03:21 PM
adding group membership to ldap users seeberg Linux - Server 0 11-09-2010 04:51 AM
best point to restrict login by ldap group membership acid_kewpie Linux - Software 0 12-18-2008 08:54 AM
filtering by group using squid + ldap as authentication hackintosh Linux - Server 3 10-25-2007 10:49 AM > Forums > Linux Forums > Linux - Software

All times are GMT -5. The time now is 11:49 AM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration