Есть система состоящая из почтового сервера и сервера оракл
Написал протой pam модуль который висит на mail сервере и является socket клиентом для приложения - socket сервера, которое в свою очередь висит на oracle сервере.
Pam модуль осуществляет аутентификацию пользователя на оракл сервере.
Есть две проблемы
1) Для работы моего модуля почему-то необходимо, чтобы в файле /etc/passwd и /etc/master.passwd существовала запись с аккаунтом пользователя. Не пойму как сделать так, чтобы был чистый Pam без создания записей в /etc/passwd
2) Поскольку я на си никогда не писал, то в моих программах возможно есть куча ошибок. Предлагаю переработать исходный код совместно
Теперь подробности реализации -
сервер oracle 8.1.7.4 на базе linux redhat 7.3
для доступа к серверу используется библиотека
libsqlora8-2.2.10
Со стороны почтового сервера -
FreeBSD 5.0
imap-uw (ipop3d и imapd) собранные с WITHOUT_SSL=yes (с ssl тоже работает, я проверял)
Вот листинги программ (прошу не бить ногами, я даже не знаю, как Makefile нарисовать поэтому покажу как компилировал ниже)
----Oracle кусок----
oracle_connector.c
----Oracle кусок----
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sqlora.h>
#define DEBUG
#define ERR -1
#define SUCCESS 1
#define BUFSZ 128
struct optionstruct {
char where[257];
char connectString[65];
char table[30];
char usercolumn[17];
char passwdcolumn[30];
};
struct optionstruct options = {
"uss_sl_type='MAIL'",
"user/password@servername",
"abs.ct_user_services",
"uss_logname",
"uss_password"
};
/* Global Variables */
int dbh = -1;
int db_connect (void);
void db_close( void );
void db_close ( void )
{
if (dbh < 0)
{
return; /* closed already ? */
}
sqlo_finish(dbh);
dbh = -1;
}
int db_connect ( void )
{
int retvalue = ERR;
char* conn_string;
int conn_count;
retvalue = -1;
if ( dbh >= 0 )
return SUCCESS;
sqlo_init(0);
if (0 <= (dbh = sqlo_connect(&dbh, options.connectString)))
{
retvalue = SUCCESS;
}
if ( retvalue != SUCCESS )
{
syslog(LOG_INFO, "oracle_connector: Oracle err %s\n", sqlo_geterror(dbh));
}
return retvalue;
}
char *db_getpasswd (const char *user)
{
char *p;
char *sql;
char *escapeUser; // User provided stuff MUST be escaped
int ncount;
const char *retvalue = NULL;
int sth;
const char **v;
sql = (char *) malloc (110 + strlen(user) + strlen(options.where));
if ( !sql )
return "ERR";
escapeUser = malloc(sizeof(char) * (strlen(user) * 2) + 1);
if ( escapeUser == NULL )
{
syslog(LOG_ERR, "oracle_connector: Insufficient memory to allocate user or password escape strings");
syslog(LOG_ERR, "oracle_connector: UNABLE TO AUTHENTICATE");
return "ERR";
}
escapeUser = (char*) user;
// D (("options.crypt=%d|\n", options.crypt));
sprintf(sql, "select %s from %s where %s='%s' ",
options.passwdcolumn,options.table,
options.usercolumn,escapeUser,escapeUser);
if ( strlen(options.where) > 0 )
{
sprintf(sql, "%s and %s", sql, options.where);
}
printf("%s\n",sql);
//ncount = sqlo_run(dbh, sql, 0 , NULL);
//if (sth == SQLO_ERROR)
if (0> (sth = sqlo_open(dbh, sql, 0, NULL)))
{
syslog(LOG_ERR, sqlo_geterror (dbh));
syslog(LOG_ERR, "Help1 hoi=%s|\n", sqlo_geterror(dbh));
return "ERR";
}
while (0==sqlo_fetch(sth,1)) {
v=sqlo_values(sth,NULL,0);
p=v[0];
//return "%s",v[0];
return p;
}
if (0 != sqlo_close(sth)) {
printf("select failed to close cursor: %s\n",sqlo_geterror(dbh));
return "ERR";
}
}
int main() {
int ret;
char *pass;
char *pw;
char key[2];
int s, c, sz,i;
struct sockaddr_in ssa, csa;
struct sockaddr *sp, *cp;
struct hostent *rhost;
char *host, *tstr;
char buf[BUFSZ];
char *userget;
char username;
const char sss;
time_t itime;
sp=(struct sockaddr *)&ssa;
cp=(struct sockaddr *)&csa;
sz=sizeof(ssa);
// Создаём сокет
s=socket(AF_INET, SOCK_STREAM, 0);
if(s == -1){
perror("Невозможно создать сокет");
exit(1);
}
// Резервируем порт 1500
ssa.sin_family = AF_INET;
ssa.sin_port = htons(1500);
ssa.sin_addr.s_addr = INADDR_ANY;
if(bind(s, sp, sz) == -1){
perror("Невозможно занять порт");
exit(1);
}
// Переводим сокет в режим ожидания соединения
if(listen(s, 0) == -1){
perror("Невозможно перейти в режим ожидания");
exit(1);
}
//Установим соединение с ораклом
ret=db_connect();
printf("Oracle Connected: %d\n",ret);
while(1){
write(1,"i'm here\n",10);
// Принимаем соединение
if((c = accept(s, cp, &sz)) == -1) {
perror("Ошибка при выполнении accept");
exit(1);
}
//Получим от клиента имя пользователя
while((i=recv(c,buf,BUFSZ,0)) > 0) {
//write(1,buf,i);
userget = (char*)malloc((i)*sizeof(char));
strncpy(userget,buf,i);
userget[i]='\0';
break;
}
// Преобразуем адрес хоста отправителя в его имя
rhost=gethostbyaddr((char*)(&csa.sin_addr),
sizeof(csa.sin_addr), AF_INET);
if(h_errno){
printf("gethostbyaddr error: %d\n", h_errno);
host=inet_ntoa(csa.sin_addr);
} else {
host=rhost->h_name;
}
// Получаем строку, содержащую дату и время
if((itime = time(NULL)) < 0){
perror("Не удалось получить время");
exit(1);
}
tstr = ctime(&itime);
// Выводим время поступления запроса,
// адрес и порт отправителя
printf("%s request from %s:%d, user name %s\n", tstr, host, htons(csa.sin_port),userget);
pass =(char*)malloc(30*sizeof(char));
pass =NULL;
pass = db_getpasswd(userget);
if (pass != NULL) {
pass[strlen(pass)]='\0';
printf("Password for user %s is %s\n",userget,pass);
send(c, pass, strlen(pass), 0);
}
else
{
send(c, "error", 5, 0);
}
free(userget);
free(pass);
// Закрываем соединение
close(c);
}
close(c);
close(s);
db_close();
return 1;
}
---------------------========================---------------------
Компилирую так
rm oracle_connector
gcc -o oracle_connector oracle_connector.c -lsqlora8 -lcrypt
---------------------========================---------------------
---------------------========================---------------------
---------------------========================---------------------
Вот кусок который pam модуль
---------------------========================---------------------
#include <security/pam_modules.h>
#include <stdarg.h>
#include <time.h>
#include <pwd.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//Это определит тип нашего модуля
#define PAM_SM_AUTH
#define BUFSZ 128
#define MAX_V 30
#define LOG_DEBUG 1
#define PLEASE_ENTER_PASSWORD "Password:"
int converse (pam_handle_t * pamh, int nargs, struct pam_message **message, struct pam_response **response);
int askForPassword(pam_handle_t *pamh);
int askForPassword(pam_handle_t *pamh)
{
struct pam_message msg[1], *mesg[1];
struct pam_response *resp=NULL;
char *prompt=NULL;
int i=0;
int retval;
prompt = malloc(strlen(PLEASE_ENTER_PASSWORD));
if (prompt == NULL)
{
syslog(LOG_DEBUG,"pam_test: askForPassword(), out of memory!?");
return PAM_BUF_ERR;
}
else
{
sprintf(prompt,PLEASE_ENTER_PASSWORD);
msg[i].msg = prompt;
}
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
mesg[i] = &msg[i];
retval = converse(pamh, ++i, mesg, &resp);
if (retval != PAM_SUCCESS) {
return retval;
}
return pam_set_item(pamh, PAM_AUTHTOK, resp->resp);
}
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);
if ((retval != PAM_SUCCESS)) // && (retval != PAM_CONV_AGAIN)
{
syslog(LOG_DEBUG, "pam_test: conversation failure [%s]"
, pam_strerror(pamh, retval));
}
}
else
{
syslog(LOG_DEBUG, "pam_test: couldn't obtain conversation function [%s]"
, pam_strerror(pamh, retval));
}
return retval;
}
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags
,int argc, const char **argv)
{
int retval;
const char *user;
char *passwd = NULL;
int s, sz, i;
struct sockaddr_in ssa;
struct sockaddr *sp;
struct in_addr sip;
char buf[BUFSZ];
char *str;
char key[2];
char *pw;
sp=(struct sockaddr *)&ssa;
sz=sizeof(ssa);
if(argc!=1){
// Помощь по использованию команды
printf("Использование: pam_модуль.so ip-адрес\n");
exit(1);
}
if(inet_aton(argv[0], &sip) != 1){
printf("Неправильно задан адрес сервера\n");
exit(1);
}
syslog(1,"!!!!!!!!!!!!!!!!!!-----1-----!!!!!!!!!!!!!!!!!!!!!");
retval = pam_get_user(pamh, &user, NULL);
if (retval != PAM_SUCCESS || user == NULL) {
syslog(LOG_DEBUG, "pam_test: no user specified");
return PAM_USER_UNKNOWN;
}
syslog(1,"!!!!!!!!!!!!!!!!!!-----2-----!!!!!!!!!!!!!!!!!!!!!");
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &passwd);
if (passwd == NULL) {
askForPassword(pamh);
}
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &passwd);
syslog(1,"!!!!!!!!!!!!!!!!!!-----3-----!!!!!!!!!!!!!!!!!!!!!");
if (passwd == NULL)
return PAM_AUTHINFO_UNAVAIL;
const char *host;
int pam_err;
pam_err = pam_get_item(pamh, PAM_RHOST, (const void **) &host);
if (host==NULL) {
host="localhost";
}
syslog(LOG_DEBUG,"pam_test: HOST: %s",host);
syslog(LOG_DEBUG,"pam_test: USER: %s",user);
syslog(LOG_DEBUG,"pam_test: PASS: %s",passwd);
// Создаём сокет
s=socket(AF_INET, SOCK_STREAM, 0);
if(s == -1){
perror("Невозможно создать сокет");
exit(1);
}
// Задаём адрес сервера
ssa.sin_family = AF_INET;
ssa.sin_port = htons(1500);
ssa.sin_addr = sip;
// Устанавливаем соединение
if(connect(s, sp, sz) == -1){
perror("Не удалось установить соединение");
exit(1);
}
// Посылаем login на сервер
str = user;
send(s,str,strlen(str),0);
// Получаем данные от сервера
while((i=recv(s, buf, BUFSZ, 0)) > 0) {
//pw = (char*)malloc(i*sizeof(char));
pw = (char*)malloc(13*sizeof(char));
//strncpy(pw,buf,i);
strncpy(pw,buf,13);
//pw[strlen(pw)]='\0';
pw[13]='\0';
}
strncpy(key,pw,2);
key[2] = '\0';
syslog(1,"key is %s",key);
char *cryptpass;
cryptpass = (char*)malloc(i*sizeof(char));
cryptpass=crypt(passwd,key);
cryptpass[strlen(cryptpass)]='\0';
syslog(1,"%s, %s, %d, %d",pw,cryptpass,strlen(pw),strlen(cryptpass));
retval = PAM_BUF_ERR;
if (!strcmp(pw,cryptpass)) {
syslog(1,"ПАРОЛИ СОВПАДАЮТ");
retval = PAM_SUCCESS;
}
else{
syslog(1,"ПАРОЛИ РАЗНЫЕ");
}
free(pw);
//free(cryptpass);
return retval;
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags
,int argc, const char **argv)
{
unsigned int ctrl;
int retval;
retval = PAM_SUCCESS;
return retval;
}
// Это определение необходимо для статической линковки модулей PAM в приложениях.
#ifdef PAM_STATIC
struct pam_module _pam_unix_auth_modstruct = {
"pam_test",
pam_sm_authenticate,
pam_sm_setcred,
NULL,
NULL,
NULL,
NULL,
};
#endif
--------------------========================---------------------
Компилирую так:
rm *.o
rm *.so
gcc -fPIC -c pam_test.c
gcc -shared -o pam_test.so pam_test.o -lcrypt
cp pam_test.so /usr/lib/pam_test.so
--------------------========================---------------------
Далее, в /etc/pam.d/pop3
auth required pam_test.so XX.XX.XX.XX
где XX.XX.XX.XX - это ip адрес сервера с oracle
--------------------========================---------------------
ПАМАГИТЕ ! давайте вместе доделаем всю эту байду ?
icq: 304000
mail: chepil@surgut.ru