Attached is a solution to described problem.
Subject: Adds support for default postgres hash algorithm
Author: Nirgal Vourgère <jvour...@greenpeace.org>
Bug-Debian: http://bugs.debian.org/594721
Description: Adds supports for postgres hash algorithm. It make it possible to
 set up postgresql to use pam and pam to use postgresql own shadow user table.
 Previously, it was only possible by disabling password encryption in
 postgresql.conf.
 This is requiered if you want authentication fallbacks within postgresql.
 See README file for full example.

TODO (see http://dep.debian.net/deps/dep3/):
Last-Update: 2010-08-28
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>

Index: pam-pgsql-0.7.1/src/backend_pgsql.c
===================================================================
--- pam-pgsql-0.7.1.orig/src/backend_pgsql.c
+++ pam-pgsql-0.7.1/src/backend_pgsql.c
@@ -264,7 +264,7 @@
 			rc = PAM_USER_UNKNOWN;
 		} else {
 			char *stored_pw = PQgetvalue(res, 0, 0);
-			if (!strcmp(stored_pw, (tmp = password_encrypt(options, passwd, stored_pw)))) rc = PAM_SUCCESS; 
+			if (!strcmp(stored_pw, (tmp = password_encrypt(options, user, passwd, stored_pw)))) rc = PAM_SUCCESS;
 			free (tmp);
 		}
 		PQclear(res);
@@ -275,7 +275,7 @@
 
 /* private: encrypt password using the preferred encryption scheme */
 char *
-password_encrypt(modopt_t *options, const char *pass, const char *salt)
+password_encrypt(modopt_t *options, const char *user, const char *pass, const char *salt)
 {
 	char *s = NULL;
 
@@ -310,6 +310,37 @@
 
 		}
 		break;
+		case PW_MD5_POSTGRES: {
+			/* This is the md5 variant used by postgres shadow table.
+			cleartext is password||user
+			returned value is md5||md5hash(password||user)
+			*/
+			MD5_CTX ctx;
+			char *buf;
+			unsigned char hash[16]; /* 16 is the md5 block size */
+			int i;
+			size_t unencoded_length;
+			char *unencoded;
+
+			unencoded_length = strlen(pass)+strlen(user);
+			unencoded = malloc(unencoded_length+1);
+			sprintf(unencoded, "%s%s", pass, user);
+
+			bzero(&hash, 16);
+
+			MD5Init(&ctx);
+			MD5Update(&ctx, (unsigned char const *) unencoded, unencoded_length);
+			MD5Final(hash, &ctx);
+
+			buf = (char *) malloc(36); /* 3 bytes for md5 + 32 bytes + 1 byte for \0 */
+			strcpy(buf, "md5");
+			for(i = 0; i < 16; i++)
+				sprintf(&buf[i * 2 + 3], "%.2x", hash[i]);
+
+			free(unencoded);
+			s = buf;
+		}
+		break;
 		case PW_SHA1: {
 
 			SHA1Context ctx;
Index: pam-pgsql-0.7.1/src/backend_pgsql.h
===================================================================
--- pam-pgsql-0.7.1.orig/src/backend_pgsql.h
+++ pam-pgsql-0.7.1/src/backend_pgsql.h
@@ -8,6 +8,6 @@
 PGconn * db_connect(modopt_t *options);
 int pg_execParam(PGconn *conn, PGresult **res, const char *query, const char *service, const char *user, const char *passwd, const char *rhost);
 int backend_authenticate(const char *service, const char *user, const char *passwd, const char *rhost, modopt_t *options);
-char * password_encrypt(modopt_t *options, const char *pass, const char *salt);
+char * password_encrypt(modopt_t *options, const char *user, const char *pass, const char *salt);
 
 #endif
Index: pam-pgsql-0.7.1/src/pam_pgsql.c
===================================================================
--- pam-pgsql-0.7.1.orig/src/pam_pgsql.c
+++ pam-pgsql-0.7.1/src/pam_pgsql.c
@@ -211,7 +211,7 @@
 		if (rc == PAM_SUCCESS) {
 
 			if ((rc = pam_get_confirm_pass(pamh, &newpass, PASSWORD_PROMPT_NEW, PASSWORD_PROMPT_CONFIRM, options->std_flags)) == PAM_SUCCESS) {
-				if((newpass_crypt = password_encrypt(options, newpass, NULL))) {
+				if((newpass_crypt = password_encrypt(options, user, newpass, NULL))) {
 					if(!(conn = db_connect(options))) {
 						rc = PAM_AUTHINFO_UNAVAIL;
 					}
Index: pam-pgsql-0.7.1/src/pam_pgsql_options.c
===================================================================
--- pam-pgsql-0.7.1.orig/src/pam_pgsql_options.c
+++ pam-pgsql-0.7.1/src/pam_pgsql_options.c
@@ -112,6 +112,8 @@
 					options->pw_type = PW_CRYPT;
 				} else if(!strcmp(val, "crypt_md5")) {
 					options->pw_type = PW_CRYPT_MD5;
+				} else if(!strcmp(val, "md5_postgres")) {
+					options->pw_type = PW_MD5_POSTGRES;
 				}
 			} else if(!strcmp(buffer, "debug")) {
 				options->debug = 1;
@@ -256,6 +258,7 @@
 			sprintf(modopt->query_auth, "select %s from %s where %s = %%u", modopt->column_pwd, modopt->table, modopt->column_user);
 
 		}
+		else SYSLOG("Can't build auth query");
 
 	}
 
Index: pam-pgsql-0.7.1/src/pam_pgsql_options.h
===================================================================
--- pam-pgsql-0.7.1.orig/src/pam_pgsql_options.h
+++ pam-pgsql-0.7.1/src/pam_pgsql_options.h
@@ -24,7 +24,8 @@
     PW_MD5,
     PW_CRYPT,
     PW_CRYPT_MD5,
-    PW_SHA1
+    PW_SHA1,
+    PW_MD5_POSTGRES
 } pw_scheme;
 
 typedef struct modopt_s {
Index: pam-pgsql-0.7.1/README
===================================================================
--- pam-pgsql-0.7.1.orig/README
+++ pam-pgsql-0.7.1/README
@@ -132,16 +132,20 @@
     debug               - this is a standard module option that will enable
                           debug output to syslog (takes no values)
     pw_type             - specifies the password encryption scheme, can be one
-                          of 'clear', 'md5', 'sha1', 'crypt', or 'crypt_md5'. the
-                          difference between 'md5' and 'crypt_md5' is that
-                          'md5' uses libmhash for hashing while 'crypt_md5'
-                          uses crypt() with a special salt to select md5
-                          hashing instead of DES. if one of 'crypt' or
-                          'crypt_md5' is specified, passwords always are
+                          of 'clear', 'md5', 'sha1', 'crypt', 'crypt_md5', or
+						  'md5_postgres'. The ifference between 'md5' and
+						  'crypt_md5' is that 'md5' uses libmhash for hashing
+						  while 'crypt_md5' uses crypt() with a special salt to
+						  select md5 hashing instead of DES. if one of 'crypt'
+						  or 'crypt_md5' is specified, passwords always are
                           encrypted in the respective format. however,
                           passwords in both formats may be stored in the
                           database, just as with /etc/(passwd|shadow).
                           defaults to 'clear'.
+						  'md5_postgres' uses the postgres default internal
+						  algorithm where hash is md5||md5(password+login). This
+						  is usefull for authenticating against postgres users
+						  created by the createuser postgres command.
     config_file         - alternative location of configuration file - it should be
 			  specified as module argument.
     timeout		- if specified pam-pgsql will wait for timeout
@@ -155,3 +159,12 @@
     try_first_pass	- same as previous, but doesn't fail if previous
 			  module failed to provide us with password
     echo_pass 		- displays password while being typed
+
+Example to autenticate against postgres users
+=============================================
+database = postgres
+user = postgres
+table = pg_catalog.pg_shadow
+user_column = usename
+pwd_column = passwd
+pw_type=md5_postgres
Index: pam-pgsql-0.7.1/COPYRIGHT
===================================================================
--- pam-pgsql-0.7.1.orig/COPYRIGHT
+++ pam-pgsql-0.7.1/COPYRIGHT
@@ -6,6 +6,7 @@
 Copyright (c) 2003. Joerg Wendland <joergl...@debian.org>,
 Copyright (c) 2005. Primoz Bratanic <pri...@slo-tech.com>
 Copyright (c) 2009. William Grzybowski <will...@agencialivre.com.br>
+Copyright (c) 2010. Nirgal Vourgère <jvour...@greenpeace.org>
 
 
 You are free to distribute this software under the terms of

Reply via email to