cyrus-pam_auth.c: is a PAM module which provides Cyrus IMAP authentication through MySQL database. The same approach can be applied to other software/services as well.
/*
* $Id: pam_module_authenticating_via_mysql.c,v 1.2
* 2004/12/07 15:12:38 cinar Exp $
*
* cyrus-pam_auth.c: is a PAM module which provides Cyrus IMAP
* authentication through MySQL database. The same approach
* can be applied to other software/services as well.
*
* Copyright (c) 2000 Ali Onur Cinar <cinar(a)zdo.com>
*
* Latest version may be downloaded from http://www.zdo.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version. And also please
* DO NOT REMOVE my name, and give me CREDIT when you use
* whole or a part of this program in an other program.
*
* To compile using GNU C Compiler:
* $ gcc -Wall -c -O7 -pipe -g cyrus-pam_auth.c
* $ gcc -shared -Xlinker -x -lmysqlclient \
* -L/usr/local/lib/mysql -o cyrus-pam_auth.so \
* cyrus-pam_auth.o
* $ install -c -m 755 cyrus-pam_auth.so /lib/security
* $ /sbin/ldconfig /lib/security
*
* Post-Process:
* Add the following line to your login program's PAM
* configuration file (/etc/pam.d/login):
* auth required cyrus-pam_auth.so
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <mysql/mysql.h>
#define PS_DEBUG
#define _PAM_EXTERN_FUNCTIONS
#define DB "cyrus"
#define USER "dbuser"
#define PASS "dbpasswd"
#define HOST "localhost"
#define SUCCESS 1
#include <security/pam_modules.h>
int authenticate(const char *p, const char *u);
int converse (pam_handle_t * pamh, int nargs,
struct pam_message **message, struct pam_response **response)
{
int retval;
struct pam_conv *conv;
retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv);
if (retval == PAM_SUCCESS) {
retval = conv->conv (nargs,
(const struct pam_message **) message,
response, conv->appdata_ptr);
}
return retval;
}
static void _pam_log (int err, const char *format,...)
{
va_list args;
va_start (args, format);
openlog ("pam-sql", LOG_PID, LOG_AUTH);
vsyslog (err, format, args);
va_end (args);
closelog ();
}
int askPW (pam_handle_t * pamh)
{
const char *user;
char *p;
struct pam_message msg[1], *pmsg[1];
struct pam_response *resp;
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
msg[0].msg = "passowrd:";
if (pam_get_user (pamh, &user, NULL) != PAM_SUCCESS)
return PAM_USER_UNKNOWN;
if (converse (pamh, 1, pmsg, &resp) != PAM_SUCCESS)
return PAM_CONV_ERR;
if (!resp)
return PAM_CONV_ERR;
p=resp[0].resp; resp[0].resp=NULL;
pam_set_item(pamh, PAM_AUTHTOK, p);
free(resp);
return authenticate(p, user);
}
PAM_EXTERN int pam_sm_setcred (pam_handle_t * pamh, int flags,
int argc,const char **argv)
{
// _pam_log (LOG_INFO, "set_cred called ");
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh, int flags,
int argc, const char **argv)
{
// _pam_log (LOG_INFO, "auth called");
return askPW (pamh);
}
PAM_EXTERN int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
int argc, const char **argv)
{
// _pam_log (LOG_INFO, "acct_mgmt called");
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
// _pam_log (LOG_INFO, "session opened");
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
// _pam_log (LOG_INFO, "session closed.");
return PAM_SUCCESS;
}
int authenticate(const char *p, const char *u)
{
MYSQL *sock,mysql;
MYSQL_RES *res;
char qbuf[128];
sprintf(qbuf,
"select user_id from users where username='%s' and password='%s'",
u,p);
mysql_init (&mysql);
if (!(sock = mysql_real_connect(&mysql, HOST, USER, PASS, DB, 0, NULL, 0)))
{
//_pam_log(LOG_INFO,"couldnt connect to mysql");
//perror("");
return PAM_AUTH_ERR;
}
if (mysql_select_db(sock,DB))
{
//_pam_log(LOG_INFO,"couldnt select database");
return PAM_AUTH_ERR;
}
if (mysql_query(sock,qbuf))
{
//_pam_log(LOG_INFO, qbuf);
return PAM_AUTH_ERR;
}
res = mysql_store_result(sock);
if (mysql_num_rows(res) != 1)
{
//_pam_log(LOG_INFO,"login error");
mysql_close(sock);
return PAM_AUTH_ERR;
}
else
{
//_pam_log(LOG_INFO,"logged in");
mysql_close(sock);
return PAM_SUCCESS;
}
}