Package: libpam-pgsql
Version: 0.5.2-9.3

libpam-pgsql is trying to do the following selection from postgres db :

SELECT 1 FROM %s WHERE %s='%s' AND (%s='y' OR %s='1')

this is incorrect if field has a booleat type and will alwas return
some records which results in impossibility to login.

I've replaced 'y' and '1' with 'f' and added sha1 support with help of
libgcrypt. So it is possible to authenticate users against django db.

P.S.
I've submitted similar patch before, but it wasn't free from defects :
doubtful license for sha1.c and additional option for pam_pgsql.conf.
The attached one is applied to the source after all debian patches.
--- pam_pgsql.c	2007-10-23 20:19:41.000000000 +0300
+++ pam_pgsql.c~	2007-10-23 20:13:51.000000000 +0300
@@ -18,6 +18,7 @@
 #include <sys/time.h>
 #include <libpq-fe.h>
 #include <crypt.h>
+#include <gcrypt.h>
 
 #define PAM_SM_AUTH
 #define PAM_SM_ACCOUNT
@@ -45,7 +46,8 @@
     PW_CLEAR = 1,
     PW_MD5,
     PW_CRYPT,
-    PW_CRYPT_MD5
+    PW_CRYPT_MD5,
+    PW_SHA1
 } pw_scheme;
 
 struct module_options {
@@ -124,6 +126,8 @@
             options->pw_type = PW_MD5;
         } else if(!strcmp(val, "crypt")) {
             options->pw_type = PW_CRYPT;
+        } else if(!strcmp(val, "sha1")) {
+            options->pw_type = PW_SHA1;
         } else if(!strcmp(val, "crypt_md5")) {
             options->pw_type = PW_CRYPT_MD5;
         }
@@ -406,6 +410,33 @@
                 }
             }
             break;
+        case PW_SHA1: {
+	    uint8_t *hash;
+	    int hash_len;
+	    hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
+	    unsigned int i, j;
+	    char outp[52] = "sha1$";
+	    char buf[135] = ""; //128+5+1, max pwd len + salt + 1
+	    char salt[6] = "";
+	    char *tmp;
+
+	    srand(time(NULL));
+	    for (i = 0; i < sizeof(salt)-1; i++) {
+	      sprintf(tmp,"%x",rand()%15);
+	      strcat(salt,tmp);
+	    }
+	    strcat(outp,salt);
+	    strcat(outp,"$");
+	    sprintf(buf,"%s",salt);
+	    strcat(buf,pass);
+	    hash = malloc(hash_len);
+	    gcry_md_hash_buffer(GCRY_MD_SHA1, hash, buf, strlen(buf));
+	    for (i = 0, j = 0; i < hash_len; i++, j+=2) {
+		sprintf(outp+j, "%02x", hash[i]);
+	    }
+	    s = outp;
+	}
+        break;
         case PW_CLEAR:
         default:
             s = strdup(pass);
@@ -498,6 +529,32 @@
                 }
             }
             break;
+	    case PW_SHA1: {
+		char *alg, *salt, *hash, *state;
+		char clpwd[134] = "";
+		char buf[9]="";
+		unsigned int hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
+		uint8_t *result;
+		result = malloc(hash_len);
+		unsigned int j, i;
+
+		alg = strtok_r(stored_pw, "$", &state);
+		salt = strtok_r(NULL, "$", &state);
+		hash = strtok_r(NULL, "$", &state);
+
+		strcat(clpwd,salt);
+		strcat(clpwd,passwd);
+		gcry_md_hash_buffer(GCRY_MD_SHA1, result, clpwd, strlen(clpwd));
+	        for (i = 0, j = 0; i < hash_len; i++, j+=2)
+		    sprintf(clpwd+j, "%02x", result[i]);
+
+		DBGLOG("client hash: %s", clpwd);
+
+		if(strcmp(hash,clpwd) == 0)
+		    rc = PAM_SUCCESS;
+		free(result);
+	    }
+	    break;
         }
     }
 
@@ -585,15 +642,14 @@
 
     sqlescape(user, user_s, strlen(user));  
 
-    /* if account has expired then expired_column = '1' or 'y' */
+    /* if account has expired then is_active = 'f' */
     if(options->expired_column) {
-    	DBGLOG("query: SELECT 1 FROM %s WHERE %s='%s' AND %s='y' OR %s='1'", options->table, options->user_column, user_s, options->expired_column, options->expired_column);
+    	DBGLOG("query: SELECT 1 FROM %s WHERE %s='%s' AND %s='f'", options->table, options->user_column, user_s, options->expired_column);
         if(pg_exec(options, conn, &res, 
-                   "SELECT 1 FROM %s WHERE %s='%s' AND (%s='y' OR %s='1')" ,
+                   "SELECT 1 FROM %s WHERE %s='%s' AND %s='f'" ,
                    options->table,
                    options->user_column,
                    user_s,
-                   options->expired_column,
                    options->expired_column) != 0) {
 	    free(user_s);
 
@@ -604,7 +660,7 @@
         }
         if(PQntuples(res) > 0) {
 	    free(user_s);
-
+	    DBGLOG("account expired");
             PQclear(res);
             PQfinish(conn);
             free_module_options(options);

Reply via email to