# NSS/PAM PgSQL

### Jörg Wendland

`<jorgland@sol.wohnheim.uni-ulm.de>`

### Bret Mogilefsky

`<mogul-sysauth-pgsql@gelatinous.com>`

### Wichert Akkerman

`<wichert@wiggy.net>`

### Christian Bayle

`<bayle@debian.org>`

### Russell Smith

`<mr-russ@pws.com.au>`

Copyright © 2001, 2004, 2005 Jörg Wendland, Wichert Akkerman, Russell Smith

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation. There are no invariant sections. A copy of the license is included in the section entitled "GNU Free Documentation License".

List of Examples

A.1. Database schema
A.2. Configuration file

# Preface

This document covers setup and use of the Name Service Switch (NSS) Module `libnss-pgsql.so`. Its purpose is replace the flatfile user, group and shadow databases in `/etc` with a relational database on a PostgreSQL server. It is highly configurable to fit onto most existing databases.

# Chapter 1. Prerequisites

For installation instructions please see the files `README` and `INSTALL` in the source distribution.

To use this module you will need a PostgreSQL database containing some sort of user account information. See Example A.1, “Database schema” for an example database.

# Chapter 2. Module and Database Setup

## required database structure

To use this module with a database you will need at least three tables in that database. One for account data (the information usually stored in `/etc/passwd`), one for group data (`/etc/group`) and another one storing information about groupmembership (there is a m:n relation between passwd and group so you need this weak entity). If you have an existing database you do not want to modify you can use views or table expressions (see Example A.2, “Configuration file”), of course. You can also optionally store shadow information (`/etc/shadow`) in the database as well. Depending on your security requirements another table or view may be needed.

### tables and fields

There have to be some required fields in those tables. They are described below.

passwd table (see getpwnam(3) for more information)

  - login name

  - password

  - numerical user id (uid)

  - numerical primary group id (gid)

  - login shell

  - description (gecos)

  - home directory

group table (see getgrnam(3))

  - group name

  - group password

  - numerical group id (gid)

An example database schema can be found in Example A.1, “Database schema”. See there for how to construct the groupmember table.

# Chapter 3. configuring the module

Having a working database, you must write your configfile `/etc/nss-pgsql.conf`. If you also want shadow support, you must write a second config file `/etc/nss-pgsql-root.conf` These files have a simple syntax:

    LINE      := COMMENT | EMPTY | STATEMENT
    COMMENT   := '#' <text>
    EMPTY     := ''
    STATEMENT := KEYWORD '=' <value>

With KEYWORD being one of the following (all are required):

connectionstring

  The connection string to connect to the server. You can include any valid PostgreSQL options.

getpwnam

  A query that returns passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid for a given username

getpwuid

  A query that returns passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid for a given uid

getgrnam

  A query that returns group_name, group_passwd, group_gid for a given group name

getgrgid

  A query that returns group_name, group_passwd, group_gid for a given gid

allusers

  A query that returns username, password, gecos, home_dir, shell, uid, primarygid for every user

allgroups

  A query that returns group_name, group_passwd, group_gid for every group

groups_dyn

  A query that returns a list of gid's a particular user is in. excluding their primary group.

getgroupmembersbygid

  A query that returns a list of usernames for a given gid

shadowconnectionstring

  The connection string to connect to the server for shadow connections. You can include any valid PostgreSQL options.

shadowbyname

  A query returning shadow_name, shadow_passwd, shadow_lstchg, shadow_min, shadow_max, shadow_warn, shadow_inact, shadow_expire, shadow_flag for a given username

shadow

  A query returning shadow_name, shadow_passwd, shadow_lstchg, shadow_min, shadow_max, shadow_warn, shadow_inact, shadow_expire, shadow_flag for all users

# Chapter 4. Name Service Switch Setup

| Caution
You can do serious damage to your system if you do not know what you are doing! If you are trying changes in the Name Service Switch for the very first time, consider doing that in a chroot environment or a test machine. Have at least an editor with `/etc/nsswitch.conf` open to revert your changes easily. You have been warned!

Setting up the Name Service Switch is fairly easy, given a working installation of the libnss-pgsql module. Just add an entry pgsql the passwd and group lines of `/etc/nsswitch.conf`. You can tune the behaviour with options between the entries to get a fully working system. Useful lines in `/etc/nsswitch.conf` would look like these:

    passwd: files [SUCCESS=continue] pgsql
    group:  files [SUCCESS=continue] pgsql
    shadow:  files [SUCCESS=continue] pgsql

This will make your libc look into the standard `passwd` and `group` files first and then use libnss-pgsql. The option [SUCCESS=continue] ensures that all accounts or groups are retrieved when using the iteration functions getpwent(3) and getgrent(3).

# Appendix A. Examples

Example A.1. Database schema

    -- Default table setup for nss-pgsql

    CREATE SEQUENCE group_id MINVALUE 1000 MAXVALUE 2147483647 NO CYCLE;
    CREATE SEQUENCE user_id MINVALUE 1000 MAXVALUE 2147483647 NO CYCLE;

    CREATE TABLE "group_table" (
    	"gid" int4 NOT NULL DEFAULT nextval('group_id'),
    	"groupname" character varying(16) NOT NULL,
    	"descr" character varying,
    	"passwd" character varying(20),
    	PRIMARY KEY ("gid")
    );

    CREATE TABLE "passwd_table" (
    	"username" character varying(64) NOT NULL,
    	"passwd" character varying(128) NOT NULL,
    	"uid" int4 NOT NULL DEFAULT nextval('user_id'),
    	"gid" int4 NOT NULL,
    	"gecos" character varying(128),
    	"homedir" character varying(256) NOT NULL,
    	"shell" character varying DEFAULT '/bin/bash' NOT NULL,
    	PRIMARY KEY ("username")
    );

    CREATE TABLE "usergroups" (
    	"gid" int4 NOT NULL,
    	"uid" int4 NOT NULL,
    	PRIMARY KEY ("gid", "uid"),
    	CONSTRAINT "ug_gid_fkey" FOREIGN KEY ("gid") REFERENCES "groups"("gid"),
    	CONSTRAINT "ug_uid_fkey" FOREIGN KEY ("uid") REFERENCES "accounts"("uid")
    );

    CREATE TABLE "shadow_table" (
     	"username" character varying(64) NOT NULL,
     	"passwd" character varying(128) NOT NULL,
     	"lastchange" int4 NOT NULL,
     	"min" int4 NOT NULL,
     	"max" int4 NOT NULL,
     	"warn" int4 NOT NULL,
     	"inact" int4 NOT NULL,
     	"expire" int4 NOT NULL,
     	"flag" int4 NOT NULL,
     	PRIMARY KEY ("username")
    );

Example A.2. Configuration file

    connectionstring        = hostaddr=127.0.0.1 dbname=unix user=postgres password=XXX connect_timeout=1
    # you can use anything postgres accepts as table expression

    # Must return "usernames", 1 column, list
    getgroupmembersbygid    = SELECT username FROM group_table WHERE gid = $1
    # Must return passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid
    getpwnam        = SELECT username, passwd, gecos, homedir, shell, uid, gid FROM passwd_table WHERE username = $1
    # Must return passwd_name, passwd_passwd, passwd_gecos, passwd_dir, passwd_shell, passwd_uid, passwd_gid
    getpwuid        = SELECT username, passwd, gecos, homedir, shell, uid, gid FROM passwd_table WHERE uid = $1
    # All users
    allusers        = SELECT username, passwd, gecos, homedir, shell, uid, gid FROM passwd_table
    # Must return group_name, group_passwd, group_gid
    getgrnam        = SELECT groupname, passwd, gid FROM group_table WHERE groupname = $1
    # Must return group_name, group_passwd, group_gid
    getgrgid        = SELECT groupname, passwd, gid FROM group_table WHERE gid = $1
    # Must return gid.  %s MUST appear first for username match in where clause
    groups_dyn      = SELECT ug.gid FROM passwd_table JOIN usergroups USING (uid) where username = $1 and ug.gid <> $2
    allgroups       = SELECT groupname, passwd, gid  FROM group_table

    # example configfile for PostgreSQL NSS module
    # this file must be readable for root only

    shadowconnectionstring        = hostaddr=127.0.0.1 dbname=unix user=postgres connect_timeout=1

    #Query in the following format
    #shadow_name, shadow_passwd, shadow_lstchg, shadow_min, shadow_max, shadow_warn, shadow_inact, shadow_expire, shadow_flag
    shadowbyname = SELECT * FROM shadow_table WHERE username = $1
    shadow = SELECT * FROM shadow_table