/*
* The Spread Toolkit.
*
* The contents of this file are subject to the Spread Open-Source
* License, Version 1.0 (the ``License''); you may not use
* this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.spread.org/license/
*
* or in the file ``license.txt'' found in this distribution.
*
* Software distributed under the License is distributed on an AS IS basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Creators of Spread are:
* Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
*
* Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
*
* All Rights Reserved.
*
* Major Contributor(s):
* ---------------
* Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
* Theo Schlossnagle jesus@omniti.com - Perl, skiplists, autoconf.
* Dan Schoenblum dansch@cnds.jhu.edu - Java interface.
* John Schultz jschultz@cnds.jhu.edu - contribution to process group membership.
*
*/
/* Implements the functions required by the struct auth_hooks in a basic way
* that authenticates users based on a clear-text password that they send to
* the daemon.
*
* This works on an implicit DENY ALL, and only those users listed in the
* spread.password file can connect.
*/
#include "arch.h"
#include "acm.h"
#include "session.h"
#include "sess_body.h" /* for Sessions[] */
#include "alarm.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef ARCH_PC_WIN95
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef ARCH_SPARC_SOLARIS
#include <sys/uio.h>
#endif
#include <sys/ioctl.h>
#else /* ARCH_PC_WIN95 */
#include <winsock.h>
#define ioctl ioctlsocket
#endif /* ARCH_PC_WIN95 */
#define MAX_PWORD_USERNAME 32
#define MAX_PWORD_PASSWORD 8
#define MAX_PWORD_CRYPTPASSWORD 13
struct user_password {
char username[MAX_PWORD_USERNAME + 1];
char crypt_pass[MAX_PWORD_CRYPTPASSWORD + 1];
struct user_password *next;
};
/* ACM callbacks */
void pword_auth_client_connection(struct session_auth_info *sess_auth_p);
void pword_auth_monitor_connection(mailbox mbox, int32 ip_addr);
/* internal utility functions */
static void insert_user(char *username, char *crypt_password);
static bool lookup_user(char *username, struct user_password **user_h);
static bool check_password(char *username, char *clear_password);
static void auth_client_conn_read(int fd, int dummy, struct session_auth_info *sess_auth_p);
static struct auth_ops Pword_ops = {
pword_auth_client_connection,
pword_auth_monitor_connection,
NULL /* deliver_authinfo */
};
static struct user_password *Users;
void pword_init(void)
{
char file_name[80];
FILE *fp;
char username[MAX_PWORD_USERNAME + 1];
char password[MAX_PWORD_CRYPTPASSWORD + 1];
char line[132];
char *ret;
int iret;
bool file_done = FALSE;
sprintf(file_name, "spread.access_pword");
Alarmp( SPLOG_DEBUG, ACM, "pword_init: Starting\n");
if (!Acm_auth_add_method("PWORD", &Pword_ops))
{
Alarmp( SPLOG_FATAL, ACM, "pword_init: Failed to register PWORD. Too many ACM methods registered. Recompile with larger limit.\n");
}
/* load spread.access_ip file */
if (NULL != (fp = fopen(file_name,"r")) )
Alarmp( SPLOG_INFO, ACM, "pword_init: using file: %s\n", file_name);
if (fp == NULL)
if (NULL != (fp = fopen(SPREAD_ETCDIR "/spread.access_pword", "r")) )
Alarmp( SPLOG_INFO, ACM, "pword_init: using file: " SPREAD_ETCDIR "/spread.access_pword\n");
if (fp == NULL)
Alarmp( SPLOG_FATAL, ACM, "pword_init: error opening config file %s in any of the standard locations. Please make sure the file exists\n", file_name);
do{
ret = fgets(line,132,fp);
if (ret == NULL)
break;
if ( line[0] == '#')
continue;
ret = strchr(line, ':' );
if ( ret == NULL)
{
Alarmp( SPLOG_ERROR, ACM, "pword_init: incomplete line: %s\n", line);
file_done = TRUE;
break;
}
*ret = ' ';
if (file_done) break;
iret = sscanf(line,"%32s %13s",username,password);
if( iret < 2 )
Alarmp(SPLOG_FATAL, ACM, "pword_init: not a valid username:password entry. line: %s\n", line);
Alarmp( SPLOG_INFO, ACM, "pword_init: loaded user %s with crypted password %s\n",username, password);
insert_user(username, password);
} while(TRUE);
fclose(fp);
}
static void insert_user(char *username, char *crypt_password)
{
struct user_password *new_user;
new_user = malloc(sizeof(struct user_password));
if (!new_user)
Alarmp(SPLOG_FATAL, ACM, "insert_user: Failed to allocate a struct user_password\n");
memcpy(new_user->username, username, MAX_PWORD_USERNAME);
memcpy(new_user->crypt_pass, crypt_password, MAX_PWORD_CRYPTPASSWORD);
if (!Users)
{
Users = new_user;
return;
}
new_user->next = Users;
Users = new_user;
}
static bool lookup_user(char *username, struct user_password **user_h)
{
struct user_password *user_p;
bool allowed;
user_p = Users;
allowed = FALSE;
/* Search allowed lists */
while(user_p)
{
Alarmp( SPLOG_INFO, ACM, "lookup_user: Checking user: %s with crypted password %s\n", user_p->username, user_p->crypt_pass);
if (!strncmp(username, user_p->username, MAX_PWORD_USERNAME) )
{
Alarmp( SPLOG_INFO, ACM, "lookup_user: Found user %s = %s with crypted password %s\n", username, user_p->username, user_p->crypt_pass);
*user_h = user_p;
return(TRUE);
}
user_p = user_p->next;
}
*user_h = NULL;
return(FALSE);
}
static bool check_password(char *username, char *clear_password)
{
struct user_password *user_p;
char *crypt_presented_pass;
char salt[2];
/* Search allowed lists */
if (lookup_user(username, &user_p))
{
memcpy(salt, user_p->crypt_pass, 2);
crypt_presented_pass = crypt(clear_password, salt);
if (!strncmp(crypt_presented_pass, user_p->crypt_pass, 13)) {
return(TRUE);
} else {
Alarmp( SPLOG_WARNING, ACM, "pword_auth_client_connection: Password (%s) did NOT match (%s) for user %s\n", crypt_presented_pass, user_p->crypt_pass, username);
return(FALSE);
}
} else {
/* user not found */
return(FALSE);
}
}
void pword_auth_client_connection(struct session_auth_info *sess_auth_p)
{
/* Get username and password from client library */
E_attach_fd(sess_auth_p->mbox, READ_FD, (void (*)(int, int, void *)) auth_client_conn_read, 0, sess_auth_p, LOW_PRIORITY);
E_attach_fd(sess_auth_p->mbox, EXCEPT_FD, (void (*)(int, int, void *)) auth_client_conn_read, 0, sess_auth_p, LOW_PRIORITY);
return;
}
static void auth_client_conn_read(mailbox mbox, int dummy, struct session_auth_info *sess_auth_p)
{
char username[MAX_PWORD_USERNAME + 1];
char clear_password[MAX_PWORD_PASSWORD + 1];
int ioctl_cmd, ret;
unsigned char response;
E_detach_fd(mbox, READ_FD);
E_detach_fd(mbox, EXCEPT_FD);
#if 0
/* temporarily disabled to test race bug */
/* set file descriptor to non-blocking */
ioctl_cmd = 1;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
#endif
ret = recv( mbox, username, MAX_PWORD_USERNAME, 0 );
if( ret < 0 )
{
Alarmp( SPLOG_WARNING, ACM, "auth_client_conn_read: reading username string failed on mailbox %d\n", mbox );
ioctl_cmd = 0;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
Sess_session_report_auth_result( sess_auth_p, FALSE);
return;
}
if( ret < MAX_PWORD_USERNAME )
{
Alarmp( SPLOG_WARNING, ACM, "auth_client_conn_read: reading username string SHORT on mailbox %d\n", mbox );
ioctl_cmd = 0;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
Sess_session_report_auth_result( sess_auth_p, FALSE);
return;
}
username[MAX_PWORD_USERNAME] = '\0';
ret = recv( mbox, clear_password, MAX_PWORD_PASSWORD, 0 );
if( ret < 0 )
{
Alarmp( SPLOG_WARNING, ACM, "auth_client_conn_read: reading password string failed on mailbox %d\n", mbox );
/* set blocking and return failure to auth */
ioctl_cmd = 0;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
Sess_session_report_auth_result( sess_auth_p, FALSE);
return;
}
if( ret < MAX_PWORD_PASSWORD )
{
Alarmp( SPLOG_WARNING, ACM, "auth_client_conn_read: reading password string SHORT on mailbox %d\n", mbox );
ioctl_cmd = 0;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
Sess_session_report_auth_result( sess_auth_p, FALSE);
return;
}
clear_password[MAX_PWORD_PASSWORD] = '\0';
/* set file descriptor back to blocking */
ioctl_cmd = 0;
ret = ioctl( mbox, FIONBIO, &ioctl_cmd);
if ( check_password(username, clear_password) )
{
response = 1;
send( mbox, &response, 1, 0);
Sess_session_report_auth_result( sess_auth_p, TRUE );
} else {
response = 0;
send( mbox, &response, 1, 0);
Sess_session_report_auth_result( sess_auth_p, FALSE );
}
return;
}
void pword_auth_monitor_connection(mailbox mbox, int32 ip_addr)
{
/* Mon_Connection_Allowed(); */
}
syntax highlighted by Code2HTML, v. 0.9.1