This patch allows you to query postgres database when user is not found in the local passwd file. I use this patch to query database with over a 100,000 users and it works quite nice. To apply the patch untar qmail-1.03.tar.gz and then run patch -p0 < pgsql_getpasswd.diff Compile qmail. The only file that is different from standart qmail installation is qmail-getpw To use the database you must setup a table looking like this one: CREATE TABLE passwd( login VARCHAR(32), home VARCHAR(128), uid int, gid int, PRIMARY KEY(login) ) then create config file /var/qmail/control/pgsql_server with the following fields in it: host port database username password table Example /var/qmail/control/pgsql_server sql.host.com 5432 users sqlusr nopass passwd To test the installation run qmail-getpw with parameter some username that you fill in the sql table. - Georgi Chorbadzhiyski georgi@unixsol.org http://georgi.unixsol.org/ diff -ur qmail-1.03/Makefile qmail-1.03-pgsql/Makefile --- qmail-1.03/Makefile Mon Jun 15 13:53:16 1998 +++ qmail-1.03-pgsql/Makefile Tue Nov 20 13:37:56 2001 @@ -1108,10 +1108,11 @@ > qmail-control.5 qmail-getpw: \ -load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \ -auto_usera.o - ./load qmail-getpw case.a substdio.a error.a str.a fs.a \ - auto_break.o auto_usera.o +load qmail-getpw.o case.a control.o getln.a open.a substdio.a error.a str.a \ +fs.a auto_break.o auto_usera.o auto_qmail.o + ./load qmail-getpw case.a control.o getln.a open.a substdio.a error.a \ + str.a fs.a stralloc.a alloc.a auto_break.o auto_usera.o auto_qmail.o \ + -lpq qmail-getpw.0: \ qmail-getpw.8 diff -ur qmail-1.03/qmail-getpw.c qmail-1.03-pgsql/qmail-getpw.c --- qmail-1.03/qmail-getpw.c Mon Jun 15 13:53:16 1998 +++ qmail-1.03-pgsql/qmail-getpw.c Tue Nov 20 14:35:12 2001 @@ -1,6 +1,11 @@ #include #include #include +#include +#include "open.h" +#include "control.h" +#include "stralloc.h" +#include "auto_qmail.h" #include "readwrite.h" #include "substdio.h" #include "subfd.h" @@ -21,6 +26,110 @@ char *dash; char *extension; +struct passwd *getpwnam_pgsql(char *username) { + int i = 0; + int current = 0; + char *ptmp; + stralloc pghost = {0}; + stralloc pgport = {0}; + stralloc pgdb = {0}; + stralloc pguser = {0}; + stralloc pgpass = {0}; + stralloc pgtable = {0}; + stralloc squery = {0}; + stralloc pgtmp = {0}; + stralloc pwname = {0}; + stralloc pwhome = {0}; + PGconn *pgconn; + PGresult *res; + static struct passwd pwd; + + // Sanitize username + while (username[i]) + { + if (username[i] == '\'' || username[i] == '\\') + username[i] = ' '; + i++; + } + // Read config + if (chdir(auto_qmail) == -1) { return NULL; }; + if (control_readfile(&pgtmp,"control/pgsql_server",0)) {; + ptmp = pgtmp.s; + while (*ptmp == ' ' || *ptmp == '\t') { + ptmp++; + } + while (*ptmp) { + if (*ptmp == ' ' || *ptmp == '\t') { + while (*ptmp == ' ' || *ptmp == '\t') { + ptmp++; + } + current++; + } + if (*ptmp != '\n') { + switch (current) { + case 0: stralloc_append(&pghost,ptmp); break; + case 1: stralloc_append(&pgport,ptmp); break; + case 2: stralloc_append(&pgdb,ptmp); break; + case 3: stralloc_append(&pguser,ptmp); break; + case 4: stralloc_append(&pgpass,ptmp); break; + case 5: stralloc_append(&pgtable,ptmp); break; + } + } + ptmp++; + } + if (!pghost.s) { fprintf(stderr,"%s\n","PGhost not defined!"); return NULL; } + if (!pgport.s) { fprintf(stderr,"%s\n","PGport not defined!"); return NULL; } + if (!pgdb.s) { fprintf(stderr,"%s\n","PGdb not defined!"); return NULL; } + if (!pguser.s) { fprintf(stderr,"%s\n","PGuser not defined!"); return NULL; } + if (!pgpass.s) { fprintf(stderr,"%s\n","PGpass not defined!"); return NULL; } + if (!pgtable.s){ fprintf(stderr,"%s\n","PGtable not defined!"); return NULL; } + stralloc_cats(&squery,"SELECT login,home,uid,gid FROM "); + stralloc_cats(&squery,pgtable.s); + stralloc_cats(&squery," WHERE login='"); + stralloc_cats(&squery,username); + stralloc_cats(&squery,"'"); + stralloc_0(&squery); + } else { + return NULL; + } + + pgconn = PQsetdbLogin (pghost.s,pgport.s,NULL,NULL,pgdb.s,pguser.s,pgpass.s); + if (PQstatus (pgconn) == CONNECTION_BAD) + { + fprintf(stderr, "SQL error: %s", PQerrorMessage(pgconn)); + PQfinish (pgconn); + _exit(QLX_SYS); + } + + res = PQexec (pgconn, squery.s); + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0) + { + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "SQL error: %s", PQerrorMessage(pgconn)); + } + PQclear(res); + PQfinish(pgconn); + return NULL; + } + + stralloc_copys(&pwname, PQgetvalue(res,0,0)); + stralloc_0(&pwname); + stralloc_copys(&pwhome, PQgetvalue(res,0,1)); + stralloc_0(&pwhome); + + pwd.pw_name = pwname.s; + pwd.pw_dir = pwhome.s; + pwd.pw_uid = atoi( PQgetvalue (res,0,2) ); + pwd.pw_gid = atoi( PQgetvalue (res,0,3) ); + pwd.pw_gecos = ""; + pwd.pw_shell = ""; + + PQclear(res); + PQfinish(pgconn); + + return &pwd; +} + int userext() { char username[GETPW_USERLEN]; @@ -36,6 +145,9 @@ errno = 0; pw = getpwnam(username); if (errno == error_txtbsy) _exit(QLX_SYS); + if (!pw) { + pw = getpwnam_pgsql(username); + } if (pw) if (pw->pw_uid) if (stat(pw->pw_dir,&st) == 0) {