Open brong opened 17 years ago
From: Kwiatek
This two files provides pgsql auth mechanism for saslauthd: They need to be putted in saslauthd directory, and require manual changes in Makefile, saslauthd.c files.
auth_pgsql.h
char auth_pgsql(const char , const char , const char , const char *); int auth_pgsql_init(void);
typedef struct pgsql_conf { char dbhost[PGSQL_BUF_LEN]; char dbport[PGSQL_BUF_LEN]; char dbuser[PGSQL_BUF_LEN]; char dbpass[PGSQL_BUF_LEN]; char database[PGSQL_BUF_LEN]; char select[PGSQL_BUF_LEN]; int verbose; } PGSQL_CONF;
typedef struct pgsql { PGconn ld; char status; PGSQL_CONF conf; } PGSQL;
auth_pgsql.c:
typedef struct pgsql_hash_rock { const char *mda; int salted; } PGSQL_HASH_ROCK;
typedef struct pgsql_password_scheme { char hash; int (check) (const char cred, const char passwd, void rock); void rock; } PGSQL_PASSWORD_SCHEME;
static int pgsql_check_hashed(const char hash, const char passwd, void rock); static int pgsql_check_crypt(const char hash,const char passwd,void rock attribute((unused))); int pgsql_init(const char *configfile, PGSQL *ret); static int pgsql_config(const char configfile,PGSQL_CONF *ret); static int pgsql_config_read(PGSQL_CONF conf, const char configfile); static int pgsql_check_password( const char hash,const char passwd,void rock attribute((unused))); static int pgsql_verify_password(PGSQL pgsql, const char user,const char service,const char realm,const char *password);
static PGSQL_HASH_ROCK hash_rock[] = {
{ "md5", 0 },
{ "md5", 1 },
{ "sha", 0 },
{ "sha", 1 },
{ "sha1", 0 },
{ "sha1", 1 }
};
static PGSQL_PASSWORD_SCHEME password_scheme[] = { { "{CRYPT}", pgsql_check_crypt, NULL }, { "{UNIX}", pgsql_check_crypt, NULL },
{ "{MD5}", pgsql_check_hashed, &hash_rock[0] },
{ "{SMD5}", pgsql_check_hashed, &hash_rock[1] },
{ "{SHA}", pgsql_check_hashed, &hash_rock[2] },
{ "{SSHA}", pgsql_check_hashed, &hash_rock[3] },
{ "{SHA1}", pgsql_check_hashed, &hash_rock[4] },
{ "{SSH1A}", pgsql_check_hashed, &hash_rock[5] },
{ NULL, NULL, NULL }
};
/ FUNCTION: auth_ldap /
const char *SASLAUTHD_CONF_FILE = SASLAUTHD_CONF_FILE_DEFAULT;
int pgsql_init(const char *configfile, PGSQL *ret) { PGSQL pgsql; int rc;
pgsql=*ret;
if (pgsql!=NULL) { return PGSQL_OK; };
pgsql=(PGSQL *)malloc(sizeof(PGSQL)); if (pgsql==NULL) return PGSQL_NOMEM;
pgsql->status=PGSQL_NOT_CONNECT; pgsql->ld=NULL; rc = pgsql_config(configfile,&pgsql->conf); if (rc!=0) { free(pgsql); return rc; };
OpenSSL_add_all_digests();
*ret=pgsql; return PGSQL_OK; };
static int pgsql_config(const char *configfile,PGSQL_CONF *ret) { PGSQL_CONF conf; int rc=0;
conf=malloc(sizeof(PGSQL_CONF)); if (conf==NULL) { return PGSQL_NOMEM; };
memset(conf,0,sizeof(PGSQL_CONF)); strlcpy(conf->dbhost,"localhost",PGSQL_BUF_LEN); strlcpy(conf->select,"select password from users where uid='%s'",PGSQL_BUF_LEN); conf->verbose=0;
rc = pgsql_config_read(conf, configfile); if (rc!=0) { if (conf!=NULL) { memset(conf,0,sizeof(PGSQL_CONF)); free(conf); } return rc; }; *ret=conf; return PGSQL_OK; };
static int pgsql_config_read(PGSQL_CONF conf, const char configfile) { FILE in; int lineno=0; char buf[2048]; char p,*key;
static int pgsql_config_int(const char val) { if (!val) return 0; if (!isdigit((int) val) && (*val != '-' || !isdigit((int) val[1]))) return 0; return atoi(val); }
in = fopen(configfile, "r"); if (!in) { syslog(LOG_ERR|LOG_LOCAL5,"Could not open saslauthd config file: %s (%m)",configfile); return -1; };
while (fgets(buf, sizeof(buf), in)) { lineno++;
if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
for (p = buf; *p && isspace((int) *p); p++);
if (!*p || *p == '#') continue;
key=p;
while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
if (isupper((int) *p))
*p = tolower(*p);
p++; };
if (*p!=':') return -1;
*p++ = '\0';
while (*p && isspace((int) *p)) p++;
if (!*p) return -1;
if (!strcasecmp(key, "pgsql_server"))
strlcpy(conf->dbhost, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_port"))
strlcpy(conf->dbport, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_username"))
strlcpy(conf->dbuser, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_password"))
strlcpy(conf->dbpass, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_database"))
strlcpy(conf->database, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_select"))
strlcpy(conf->select, p, PGSQL_BUF_LEN);
else if (!strcasecmp(key, "pgsql_verbose"))
conf->verbose=pgsql_config_int(p);
};
fclose(in);
return PGSQL_OK; };
char *pgsql_error( const int errno) {
switch (errno) {
case PGSQL_OK:
return "Success";
case PGSQL_FAIL:
return "Generic error";
case PGSQL_NOMEM:
return "Out of memory";
case PGSQL_RETRY:
return "Retry condition (pgsql server connection reset or broken)";
case PGSQL_NOT_GROUP_MEMBER:
return "Group member check failed";
case PGSQL_INVALID_PASSWORD:
return "Invalid password";
case PGSQL_USER_NOT_FOUND:
return "User not found";
case PGSQL_CONNECT_FAIL:
return "Cannot connect to pgsql server (configuration error)";
default:
return "Unknow error";
}
}
static int pgsql_check_crypt(const char hash,const char passwd,void rock attribute((unused))) { char cred;
if (strlen(hash) < 2 ) return PGSQL_INVALID_PASSWORD;
cred = crypt(passwd, hash); if (EMPTY(cred)) return PGSQL_INVALID_PASSWORD; return strcmp(hash, cred) ? PGSQL_INVALID_PASSWORD : PGSQL_OK; }
static int pgsql_check_hashed(const char hash, const char passwd, void rock)
{
int rc, dlen;
PGSQL_HASH_ROCK hrock = (PGSQL_HASH_ROCK ) rock;
EVP_MD_CTX mdctx;
const EVP_MD md;
unsigned char digest[EVP_MAX_MD_SIZE];
char dg[256];
char
ch[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
int i;
md = EVP_get_digestbyname(hrock->mda); if (!md) { syslog(LOG_ERR|LOG_LOCAL5,"unknown digest type[%s]", hrock->mda); return PGSQL_FAIL; };
EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, md, NULL); EVP_DigestUpdate(&mdctx,passwd,strlen(passwd)); EVP_DigestFinal_ex(&mdctx, digest, &dlen); EVP_MD_CTX_cleanup(&mdctx);
rc=0; for(i = 0; i < dlen; i++) { dg[rc]=ch[(digest[i] & 0xf0)>>4]; rc ++; dg[rc]=ch[(digest[i] & 0xf)]; rc ++; }; dg[rc]='\0';
rc = strncmp(dg, (char *)hash, rc); return rc ? PGSQL_INVALID_PASSWORD : PGSQL_OK; }
static int pgsql_verify_password(PGSQL pgsql, const char user,const char service,const char realm,const char password) { int i, hlen; PGresult res; char select[2048]; char *getp;
if (EMPTY(password)) return PGSQL_INVALID_PASSWORD;
snprintf(select,2048,pgsql->conf->select,user);
res=PQexec(pgsql->ld,select); if (!res || PQresultStatus(res)!=PGRES_TUPLES_OK) { syslog(LOG_ERR|LOG_LOCAL5,"cant exec pgsql select: %s",PQerrorMessage(pgsql->ld)); PQclear(res); return PGSQL_FAIL; };
if (PQntuples(res)!=1) { syslog(LOG_ERR|LOG_LOCAL5,"no single entry for user [%s]",user); PQclear(res); return PGSQL_USER_NOT_FOUND; }; getp=PQgetvalue(res,0,0);
i=pgsql_check_password(getp,password,NULL); PQclear(res); return i; }
static int pgsql_check_password( const char hash,const char passwd,void *rock attribute((unused))) { int i,hlen;
if (EMPTY(hash)) return PGSQL_INVALID_PASSWORD;
if (EMPTY(passwd)) return PGSQL_INVALID_PASSWORD;
for (i = 0; password_scheme[i].hash != NULL; i++) { hlen = strlen(password_scheme[i].hash); if (!strncasecmp(password_scheme[i].hash, hash, hlen)) { if (password_scheme[i].check) { return (password_scheme[i].check)(hash+hlen, passwd, password_scheme[i].rock); } return PGSQL_FAIL; } } return strcmp(hash, passwd) ? PGSQL_INVALID_PASSWORD : PGSQL_OK; };
PGconn pgsql_connect(PGSQL pgsql) { PGconn *cn;
cn=PQsetdbLogin( pgsql->conf->dbhost!=NULL?pgsql->conf->dbhost:NULL, pgsql->conf->dbport!=NULL?pgsql->conf->dbport:NULL, NULL,NULL, pgsql->conf->database!=NULL?pgsql->conf->database:NULL, pgsql->conf->dbuser!=NULL?pgsql->conf->dbuser:NULL, pgsql->conf->dbpass!=NULL?pgsql->conf->dbpass:NULL );
if (PQstatus(cn)==CONNECTION_BAD) { PQfinish(cn); return NULL; }; return cn; };
int pgsql_authenticate(PGSQL pgsql,const char user,const char service,const char realm,const char *password) { int i,rc; int retry=2;
if (pgsql==NULL) { syslog(LOG_ERR|LOG_LOCAL5,"pgsql_init did not run."); return PGSQL_FAIL; };
if (pgsql->ld==NULL) { PGconn *conn; conn=pgsql_connect(pgsql); pgsql->ld=conn; pgsql->status=PGSQL_CONNECT; };
if (pgsql->ld==NULL) { syslog(LOG_ERR|LOG_LOCAL5,"Cant connect to psql server"); return PGSQL_CONNECT_FAIL; };
for (;retry > 0; retry--) { rc=pgsql_verify_password(pgsql,user,service,realm,password); switch(rc) { case 0: return PGSQL_OK; case 1: if (retry>1) { syslog(LOG_INFO|LOG_LOCAL5,"Retrying authentication"); break; } default: syslog(LOG_DEBUG|LOG_LOCAL5, "Authentication failed for %s%s%s: %s(%d)", user, (ISSET(realm) ? "/" : ""), (ISSET(realm) ? realm : ""), pgsql_error(rc), rc); return PGSQL_FAIL; }; };
};
// end of authentication
char auth_pgsql( const char login, const char password, const char service,const char *realm ) {
static PGSQL *pgsql = NULL; int rc=0;
if (pgsql==NULL) { rc=pgsql_init(SASLAUTHD_CONF_FILE, &pgsql); if (rc!=0) { pgsql=NULL; RETURN("NO"); }; };
rc=pgsql_authenticate(pgsql,login,service,realm,password); if (rc==0) { RETURN("OK"); } else { RETURN("NO"); }
};
int auth_pgsql_init () { struct addrinfo hints; int err; char *c; if (mech_option != NULL) { SASLAUTHD_CONF_FILE = mech_option; } return 0; }
for proper compile in saslauthd.h need to put:
For more questions please ask.
From: Ken Murchison
Why not just use the existing SQL auxprop plugin? It supports ALL SASL mechanisms, not just plaintext authentication
From: Kwiatek Bugzilla-Id: 2900 Version: 2.1.x Owner: Ken Murchison