Skip to content

Instantly share code, notes, and snippets.

@alpacaaa
Created July 29, 2012 09:01
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save alpacaaa/3196852 to your computer and use it in GitHub Desktop.
Save alpacaaa/3196852 to your computer and use it in GitHub Desktop.
Use mysql for authentication in ubuntu 12.04

Authenticating users against mysql

I couldn't find any relevant information for getting this to work on ubuntu precise, so I'm writing my founds here.
It's actually pretty simple, this approach doesn't involve PAM but just NSS. The implications are clearly explained in the FAQ of the nss-mysql module:

NSS stands for NameService Switch. NSS allows you to implement access to various data using any number of modules. This means that when the operating system wants to look up the user "cinergi", it doesn't have to know how - it calls upon the NSS system to perform the task. In turn, we can now configure NSS to look for users in traditional places like /etc/passwd, NIS, LDAP, and now (using this module), MySQL. The NSS API is the backend for traditional UNIX user lookup routines like 'getpwnam' - providing details such as username, uid, gid, gecos, shell, homedirectory, password, etc. It does NOT provide for changing user details. This is where PAM comes in handy. PAM stands for Pluggable Authentication Modules. Like the name suggests, PAM allows you to implement authentication (and data manipulation) using any number of modules. Note that this differs from NSS in that it ONLY provides authentication. It does not allow you to do such things as "finger username", or create files owned by "username". Unlike NSS, however, it can enable users to change their passwords using traditional methods like the 'passwd' command. The libnss_mysql library, like the name suggests, provides an NSS-based solution. Whether you also need PAM depends upon whether you need to enable users to change their password using traditional methods (you could always script a passwd-like utility that performs MySQL commands).

So any change to users must be done against the database as regular shell commands won't work. Fair enough.
Regular users (stored in /etc/passwd) will still work (having root inside the db looks like a bad idea), so the system will first look up for a regular user as always and eventually look it up in mysql if not found.

Installing packages

There's only one package needed.

sudo apt-get install libnss-mysql-bg

Choosing passwords

You need to choose two passwords that will be assigned to the two mysql users running queries (find user, find group...).
From here on, I'll refer to $user-pass and $root-pass inside configuration files. Change it appropriately with the two passwords choosen.

Editing files

  1. Edit /etc/libnss-mysql.cfg replacing its content with this:

     getpwnam    SELECT username,'x',uid,gid,gecos,homedir,shell \
             FROM users \
             WHERE username='%1$s' \
             LIMIT 1
     getpwuid    SELECT username,'x',uid,gid,gecos,homedir,shell \
                 FROM users \
                 WHERE uid='%1$u' \
                 LIMIT 1
     getspnam    SELECT username,password,lstchg,min,max,warn,inact,expire,flag \
                 FROM users \
                 WHERE username='%1$s' \
                 LIMIT 1
     getpwent    SELECT username,'x',uid,gid,gecos,homedir,shell \
                 FROM users
     getspent    SELECT username,password,lstchg,min,max,warn,inact,expire,flag \
                 FROM users
     getgrnam    SELECT name,password,gid \
                 FROM groups \
                 WHERE name='%1$s' \
                 LIMIT 1
     getgrgid    SELECT name,password,gid \
                 FROM groups \
                 WHERE gid='%1$u' \
                 LIMIT 1
     getgrent    SELECT name,password,gid \
                 FROM groups
     memsbygid   SELECT username \
                 FROM grouplist \
                 WHERE gid='%1$u'
     gidsbymem   SELECT gid \
                 FROM grouplist \
                 WHERE username='%1$s'
    
     host        localhost
     database    auth
     username    nss-user
     password    $user-pass
     #socket      /var/run/mysqld/mysqld.sock
     #port        3306
    
  2. Edit /etc/libnss-mysql-root.cfg replacing its content with this:

     username    nss-root
     password    $root-pass
    
  3. Edit /etc/nsswitch.conf replacing the following lines:

     passwd:         compat
     group:          compat
     shadow:         compat
    

    with these:

     passwd:         compat mysql
     group:          compat mysql
     shadow:         compat mysql
    

Importing database

Run the following queries against your mysql database:

create database auth;
use auth;

# The tables ...
CREATE TABLE groups (
  name varchar(16) NOT NULL default '',
  password varchar(34) NOT NULL default 'x',
  gid int(11) NOT NULL auto_increment,
  PRIMARY KEY  (gid)
) AUTO_INCREMENT=5000;

CREATE TABLE grouplist (
  rowid int(11) NOT NULL auto_increment,
  gid int(11) NOT NULL default '0',
  username char(16) NOT NULL default '',
  PRIMARY KEY  (rowid)
);

CREATE TABLE users (
  username varchar(16) NOT NULL default '',
  uid int(11) NOT NULL auto_increment,
  gid int(11) NOT NULL default '5000',
  gecos varchar(128) NOT NULL default '',
  homedir varchar(255) NOT NULL default '',
  shell varchar(64) NOT NULL default '/bin/bash',
  password varchar(34) NOT NULL default 'x',
  lstchg bigint(20) NOT NULL default '1',
  min bigint(20) NOT NULL default '0',
  max bigint(20) NOT NULL default '99999',
  warn bigint(20) NOT NULL default '0',
  inact bigint(20) NOT NULL default '0',
  expire bigint(20) NOT NULL default '-1',
  flag bigint(20) unsigned NOT NULL default '0',
  PRIMARY KEY  (uid),
  UNIQUE KEY username (username),
  KEY uid (uid)
) AUTO_INCREMENT=5000;


# The permissions ...
GRANT USAGE ON *.* TO `nss-root`@`localhost` IDENTIFIED BY '$root-pass';
GRANT USAGE ON *.* TO `nss-user`@`localhost` IDENTIFIED BY '$user-pass';

GRANT Select (`username`, `uid`, `gid`, `gecos`, `homedir`, `shell`, `password`,
              `lstchg`, `min`, `max`, `warn`, `inact`, `expire`, `flag`)
             ON `auth`.`users`
             TO 'nss-root'@'localhost';
GRANT Select (`name`, `password`, `gid`)
             ON `auth`.`groups`
             TO 'nss-root'@'localhost';

GRANT Select (`username`, `uid`, `gid`, `gecos`, `homedir`, `shell`)
             ON `auth`.`users`
             TO 'nss-user'@'localhost';
GRANT Select (`name`, `password`, `gid`)
             ON `auth`.`groups`
             TO 'nss-user'@'localhost';

GRANT Select (`username`, `gid`)
             ON `auth`.`grouplist`
             TO 'nss-user'@'localhost';
GRANT Select (`username`, `gid`)
             ON `auth`.`grouplist`
             TO 'nss-root'@'localhost';

Remember to replace $user-pass and $root-pass. This will create the database used for authentication. Now, to create a user, just use something like the following:

INSERT INTO users (username,gecos,homedir,password)
    VALUES ('cinergi', 'Ben Goodwin', '/home/cinergi', ENCRYPT('cinergi'));
INSERT INTO groups (name)
    VALUES ('foobaz');
INSERT INTO grouplist (gid,username)
    VALUES (5000,'cinergi');

The end

That should be all there is to it. I haven't tested this deeply, but it seems to work fine. Any improvement is more than welcome.

@ogg1980
Copy link

ogg1980 commented Mar 15, 2014

Please be aware that if you use the method described above, users can login with only the first 8 characters of their passwords (if they're 8 characters or longer).

Hence the solution above isn't suited for a production environment. In such case, you're better off configuring libpam-mysql.

@markc
Copy link

markc commented Nov 26, 2014

@ogg1980 would you have any more details about exactly where this 8 char limitation resides?

@victor73
Copy link

victor73 commented Jul 1, 2015

@markc It has to do with the use of Mysql's ENCRYPT() function. See here:

https://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html#function_encrypt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment