The goal of this document is to explain how to map user accounts of 
a linux system on a postgress database. In our case on the gforge database.

The clue is the Name Service Switch aka NSS.

Extract of the nsswitch.conf manual:
------------------------------------------------------------------------------
nsswitch.conf - System Databases and Name Service Switch configuration file

DESCRIPTION
    Various functions in the C Library need to be configured to work correctly in the local environment.  Tra­
    ditionally, this was done by using files (e.g., `/etc/passwd'), but other nameservices (like  the  Network
    Information  Service  (NIS)  and the Domain Name Service (DNS)) became popular, and were hacked into the C
    library, usually with a fixed search order.

    The Linux libc5 with NYS support and the GNU C Library 2.x (libc.so.6) contain a cleaner solution of  this
    problem.   It is designed after a method used by Sun Microsystems in the C library of Solaris 2. We follow
    their name and call this scheme "Name Service Switch" (NSS). The sources for  the  "databases"  and  their
    lookup order are specified in the /etc/nsswitch.conf file.
------------------------------------------------------------------------------
Many "databases" are available in the NSS
The one that we will use are:
	passwd: User passwords, used by getpwent(3) functions.
	group : Groups of users, used by getgrent(3) functions.

shadow is not used in the nss-pgsql implementation we will use

How this works?
---------------
A service named SERVICE is implemented by a shared object library named libnss_SERVICE.so.X  that  resides
in /lib.
common ones are:
     /lib/libnss_compat.so.X  implements `compat' source for glibc2
     /lib/libnss_db.so.X      implements `db' source for glibc2
     /lib/libnss_dns.so.X     implements `dns' source for glibc2
     /lib/libnss_files.so.X   implements `files' source for glibc2
     /lib/libnss_hesiod.so.X  implements `hesiod' source for glibc2
     /lib/libnss_nis.so.X     implements `nis' source for glibc2
     /lib/libnss_nisplus.so.2 implements `nisplus' source for glibc 2.1
the one we use is:
     /lib/libnss_pgsql.so.2.0.0

Configuration files:
--------------------
/etc/nsswitch.conf 
Here you tell which "databases" you will use
This is very simple:

...
passwd:         compat pgsql
group:          compat pgsql
...

Only have to add the pgsql database for passwd and group

/etc/nss-pgsql.conf
This is the most complex part for nss-pgsql configuration

---
host            = 10.0.0.5
port            = 5432
database        = gforge
login           = gforge_nss
passwd          = ''
passwdtable     = nss_passwd
grouptable      = nss_groups
groupmembertable = nss_passwd JOIN nss_usergroups ON nss_passwd.uid=nss_usergroups.uid JOIN nss_groups ON nss_usergroups.gid=nss_groups.gid

passwd_name     = login
passwd_passwd   = passwd
passwd_uid      = uid
passwd_dir      = homedir
passwd_shell    = shell
passwd_gecos    = gecos
passwd_gid      = gid

group_name      = name
group_passwd    = passwd
group_gid       = gid
group_member    = login
---
host/port/database/login/passwd are used to connect pgsql
nss-pgsql uses internally PQconnectdb function (http://www.postgresql.org/docs/7.4/static/libpq.html)
host can be /tmp for socket connection
You have to ensure pgsql is properly configured to let the user access to the database
usually in /etc/postgresql/pg_hba.conf file
You can set a password if you want.
The rest of the config describes the mapping with database tables (passwdtable/grouptable/groupmembertable)
and fields (passwd_*/group_*) in the database.

nss_passwd/nss_groups where defined as views in gforge

Postgresql tables
-----------------
There is the first implementation without changing anything in the database

--- gforge/db/20041001.sql
CREATE VIEW nss_passwd AS
	SELECT unix_uid+20000 AS uid,
		unix_uid+20000 AS gid,
		user_name AS login,
		unix_pw AS passwd,
		realname AS gecos,
		shell,
		'/var/lib/gforge/chroot/home/users/' || user_name AS homedir
	FROM users
	WHERE status='A'
	UNION
	SELECT group_id+50000 AS uid,
		group_id+20000 AS gid,
		'anoncvs_' || unix_group_name AS login,
		CHAR(1) 'x' AS passwd,
		group_name AS gecos,
		'/bin/false' AS shell,
		'/var/lib/gforge/chroot/home/groups' || group_name AS homedir
	FROM groups
	UNION
	SELECT 9999 AS uid,
		9999 AS gid,
		'gforge_scm' AS login,
		CHAR(1) 'x' AS passwd,
		'Gforge SCM user' AS gecos,
		'/bin/false' AS shell,
		'/var/lib/gforge/chroot/home' AS homedir;

CREATE VIEW nss_shadow AS
	SELECT user_name AS login,
		unix_pw AS passwd,
		CHAR(1) 'n' AS expired,
		CHAR(1) 'n' AS pwchange
	FROM users
	WHERE status='A';

CREATE VIEW nss_groups AS
	SELECT group_id+10000 AS gid,
		unix_group_name AS name,
		group_name AS descr,
		CHAR(1) 'x' AS passwd
	FROM groups
	UNION
	SELECT unix_uid+20000 AS gid,
		user_name AS name,
		lastname AS descr,
		CHAR(1) 'x' AS passwd
	FROM users;

CREATE VIEW nss_usergroups AS
	SELECT group_id+10000 AS gid,
		users.unix_uid+20000 AS uid
	FROM user_group,users 
	WHERE user_group.user_id=users.user_id
	UNION 
	SELECT unix_uid+20000 AS gid,
		unix_uid+20000 AS uid
	FROM users
---
You will need to give some access to the gforge_nss postgresql user.
GRANT SELECT ON nss_passwd TO gforge_nss
GRANT SELECT ON nss_groups TO gforge_nss
GRANT SELECT ON nss_usergroups TO gforge_nss


Comments:
---------
nss_shadow is not used

nss_passwd is composed of the union of users for user account 
and users for cvs account

nss_group
One problem is it should be different groups for projects and for cvs since all users of a project don't
have necessarily access to cvs
All addition are making search not very efficient and probably renders indexes ineficient

nss_usergroups
It's a table of uid,gid couples describing user with uid is member of group with gid

How to solve this:
Efficiency:
	Have two tables for users and groups that would allow direct mapping, efficient indexes.
	Link this to the System class

Easyness:
	Add fields in users and groups table
	This will require the use of union, and indexes will be less efficient

On non debian install unix_uid is not used, it's rather user_id.
Hardcoded path should be replaced by database fields.

Changing uid/gid on the system is a complex thing so we should find a solution that allow to keep 
the already defined uid/gid

--------


ID:
---
For each user I need one uid=gid
For each group I need one gid for shell, one for scm
This last may cause a problem for users members of more that 16 projects
	if there is a limitation to a max of 32 groups for a user,
	so we can keep the actual situation that use the same gid for shell and scm 
We use the following:
uid from 50000 to 59999 / gid from 10000 to 19999 for projects
uid from 20000 to 49999 / gid from  20000 to 49999 for users
With different gid for shell and scm:
gid from 50000 to 59999 for scm


---------------------------------------------
anonscm-gforge user
fill /cvsroot/projectname/CVSROOT/passwd with 
anonymous:\$1\$0H\$2/LSjjwDfsSA0gaDYY5Df/:anonscm-gforge
create anonscm-gforge user
adduser --system --group --home /var/lib/gforge/chroot/cvsroot anonscm-gforge
make history files owned by anonscm-gforge
chown anonscm-gforge /cvsroot/*/CVSROOT/history

---------------------------------------------
Currently implementation replaced views with tables
see db/20050225-nsssetup.sql and changes 
between tables are triggered by 
common/include/system/pgsql.class.php
I hope soon to get some help to have this as db triggers
