/*
auth.c - MessageWall authentication definitions
Copyright (C) 2002 Ian Gulliver
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <firestring.h>
#include "dbase.h"
#include "auth.h"
#include "security.h"
#include "smtp.h"
#include "messagewall.h"
static const char tagstring[] = "$Id: auth.c,v 1.13 2002/07/16 18:37:20 ian Exp $";
int auth_reload;
void auth_clear() {
int i;
struct messagewall_relay_auth_t *relay_auth1, *relay_auth2;
for (i = 0; i < 65536; i++) {
relay_auth1 = relay_auth_hash[i];
while (relay_auth1 != NULL) {
relay_auth2 = relay_auth1;
relay_auth1 = relay_auth1->next;
firestring_estr_free(&relay_auth2->username);
firestring_estr_free(&relay_auth2->hash);
free(relay_auth2);
}
relay_auth_hash[i] = NULL;
}
}
void auth_load_relay_auth() {
struct messagewall_relay_auth_t *relay_auth1;
char *slash;
char line[1025];
unsigned int u;
FILE *f;
if (relay_auth == NULL)
return;
/*
* we're inside the chroot; everything should be root controlled and fopen shouldn't be a problem
*/
f = fopen(relay_auth,"r"); /* ITS4: ignore fopen */
if (f == NULL) {
perror("Unable to open relay_auth file");
exit(100);
}
/*
* line really does have 1025 bytes of space
*/
while (fgets(line,1025,f) != NULL) { /* ITS4: ignore fgets */
/*
* check for comment
*/
if (line[0] == '#')
continue;
firestring_chomp(line);
/*
* check for blank line
*/
if (line[0] == '\0')
continue;
/*
* make sure it's delimited
*/
slash = strchr(line,':');
if (slash == NULL)
continue;
*(slash++) = '\0';
/*
* build new object to insert
*/
relay_auth1 = messagewall_malloc(struct messagewall_relay_auth_t);
firestring_estr_alloc(&relay_auth1->username,strlen(line));
firestring_estr_strcpy(&relay_auth1->username,line);
firestring_estr_alloc(&relay_auth1->hash,strlen(slash));
firestring_estr_strcpy(&relay_auth1->hash,slash);
firestring_estr_0(&relay_auth1->hash);
/*
* calculate hash
*/
u = dbase_binary_hash(&relay_auth1->username,0);
/*
* insert into table
*/
relay_auth1->next = relay_auth_hash[u];
relay_auth_hash[u] = relay_auth1;
}
fclose(f);
}
void auth_load() {
auth_clear();
auth_load_relay_auth();
}
int auth_check_password(struct firestring_estr_t *username, struct firestring_estr_t *password) {
int c;
if (relay_auth == NULL)
return 1;
if (write(auth_writemap[process],&username->l,sizeof(username->l)) != sizeof(username->l)) {
fprintf(stderr,"{%d} AUTH/FATAL: unable to write username length",process);
exit(1);
}
if (write(auth_writemap[process],username->s,username->l) != username->l) {
fprintf(stderr,"{%d} AUTH/FATAL: unable to write username\n",process);
exit(1);
}
if (write(auth_writemap[process],&password->l,sizeof(password->l)) != sizeof(password->l)) {
fprintf(stderr,"{%d} AUTH/FATAL: unable to write password length\n",process);
exit(1);
}
if (write(auth_writemap[process],password->s,password->l) != password->l) {
fprintf(stderr,"{%d} AUTH/FATAL: unable to write password\n",process);
exit(1);
}
if (read(auth_readmap[process],&c,sizeof(c)) != sizeof(c)) {
fprintf(stderr,"{%d} AUTH/FATAL: unable to read result\n",process);
exit(1);
}
return c;
}
static int auth_internal_check_password(struct firestring_estr_t *username, struct firestring_estr_t *password) {
struct messagewall_relay_auth_t *iter;
unsigned int u;
u = dbase_binary_hash(username,0);
iter = relay_auth_hash[u];
while (iter != NULL) {
if (firestring_estr_estrcmp(&iter->username,username,0) == 0) {
/*
* we've found the user
*/
firestring_estr_0(password);
if (firestring_estr_strcmp(&iter->hash,crypt(password->s,iter->hash.s)) == 0)
return 0;
else
return 1;
}
iter = iter->next;
}
/*
* user does not exist
*/
return 1;
}
int auth_main(struct firestring_conf_t *config, int r, int w, int j) {
struct firestring_estr_t username, password;
int c;
int i;
security_context(config,SECURITY_MWALLA);
firestring_conf_free(config);
firestring_estr_alloc(&username,SMTP_LINE_MAXLEN);
firestring_estr_alloc(&password,SMTP_LINE_MAXLEN);
for (i = 0; i < 65536; i++)
relay_auth_hash[i] = NULL;
auth_load_relay_auth();
auth_reload = 0;
signal(SIGUSR2,auth_handle_usr2);
/*
* write out my pid file
*/
{
FILE *f;
char filename[512];
firestring_snprintf(filename,512,"%s/mwalla.%d.pid",pid_dir,j);
f = fopen(filename,"w");
if (f == NULL) {
perror("fopen(pid_dir/mwalla.pid)");
exit(100);
}
fprintf(f,"%d\n",getpid());
fclose(f);
}
while (1) {
username_length:
i = read(r,&username.l,sizeof(username.l));
if (i == -1 && errno == EINTR)
goto username_length;
if (i == 0) {
fprintf(stderr,"{%d} AUTH/FATAL: auth process lost connection to main process\n",process);
exit(1);
}
if (i != sizeof(username.l)) {
fprintf(stderr,"{%d} AUTH/FATAL: failed reading username length\n",process);
exit(1);
}
if (username.l > SMTP_LINE_MAXLEN) {
fprintf(stderr,"{%d} AUTH/FATAL: username too long\n",process);
exit(1);
}
username.a = username.l;
username:
i = read(r,username.s,username.l);
if (i == -1 && errno == EINTR)
goto username;
if (i != username.l) {
fprintf(stderr,"{%d} AUTH/FATAL: failed reading username\n",process);
exit(1);
}
password_length:
i = read(r,&password.l,sizeof(password.l));
if (i == -1 && errno == EINTR)
goto password_length;
if (i != sizeof(password.l)) {
fprintf(stderr,"{%d} AUTH/FATAL: failed reading password length\n",process);
exit(1);
}
if (password.l > SMTP_LINE_MAXLEN) {
fprintf(stderr,"{%d} AUTH/FATAL: password too long\n",process);
exit(1);
}
password.a = password.l;
password:
i = read(r,password.s,password.l);
if (i == -1 && errno == EINTR)
goto password;
if (i != password.l) {
fprintf(stderr,"{%d} AUTH/FATAL: failed reading password\n",process);
exit(1);
}
if (auth_reload == 1) {
auth_load();
auth_reload = 0;
}
c = auth_internal_check_password(&username,&password);
if (write(w,&c,sizeof(c)) != sizeof(c)) {
fprintf(stderr,"{%d} AUTH/FATAL: failed to write result\n",process);
exit(1);
}
}
exit(0);
}
void auth_handle_usr2(int s) {
auth_reload = 1;
fprintf(stderr,"{%d} AUTH/STATUS: received USR2, reloading authentication database\n",process);
signal(s,auth_handle_usr2);
}
syntax highlighted by Code2HTML, v. 0.9.1