@ -44,6 +44,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# include "asterisk/app.h"
# include "asterisk/astdb.h"
# include "asterisk/utils.h"
# include "asterisk/options.h"
enum {
OPT_ACCOUNT = ( 1 < < 0 ) ,
OPT_DATABASE = ( 1 < < 1 ) ,
OPT_JUMP = ( 1 < < 2 ) ,
OPT_MULTIPLE = ( 1 < < 3 ) ,
OPT_REMOVE = ( 1 < < 4 ) ,
} auth_option_flags ;
AST_APP_OPTIONS ( auth_app_options , {
AST_APP_OPTION ( ' a ' , OPT_ACCOUNT ) ,
AST_APP_OPTION ( ' d ' , OPT_DATABASE ) ,
AST_APP_OPTION ( ' j ' , OPT_JUMP ) ,
AST_APP_OPTION ( ' m ' , OPT_MULTIPLE ) ,
AST_APP_OPTION ( ' r ' , OPT_REMOVE ) ,
} ) ;
static char * tdesc = " Authentication Application " ;
@ -52,9 +69,9 @@ static char *app = "Authenticate";
static char * synopsis = " Authenticate a user " ;
static char * descrip =
" Authenticate(password[|options ]): This application asks the caller to enter a \n "
" given password in order to continue dialplan execution. If the password begins \n "
" with the '/' character, it is interpreted as a file which contains a list of\n "
" Authenticate(password[|options [|maxdigits] ]): This application asks the caller\n "
" to enter a given password in order to continue dialplan execution. If the password\n "
" begins with the '/' character, it is interpreted as a file which contains a list of\n "
" valid passwords, listed 1 password per line in the file. \n "
" When using a database key, the value associated with the key can be anything. \n "
" Users have three attempts to authenticate before the channel is hung up. If the \n "
@ -69,6 +86,10 @@ static char *descrip =
" the file. When one of the passwords is matched, the channel will have \n "
" its account code set to the corresponding account code in the file. \n "
" r - Remove the database key upon successful entry (valid with 'd' only) \n "
" maxdigits - maximum acceptable number of digits. Stops reading after \n "
" maxdigits have been entered (without requiring the user to \n "
" press the '#' key). \n "
" Defaults to 0 - no limit - wait for the user press the '#' key. \n "
;
STANDARD_LOCAL_USER ;
@ -78,13 +99,19 @@ LOCAL_USER_DECL;
static int auth_exec ( struct ast_channel * chan , void * data )
{
int res = 0 ;
int jump = 0 ;
int retries ;
struct localuser * u ;
char password [ 256 ] = " " ;
char passwd [ 256 ] ;
char * opts ;
char * prompt ;
int maxdigits ;
char * argcopy = NULL ;
struct ast_flags flags = { 0 } ;
AST_DECLARE_APP_ARGS ( arglist ,
AST_APP_ARG ( password ) ;
AST_APP_ARG ( options ) ;
AST_APP_ARG ( maxdigits ) ;
) ;
if ( ast_strlen_zero ( data ) ) {
ast_log ( LOG_WARNING , " Authenticate requires an argument(password) \n " ) ;
@ -101,37 +128,49 @@ static int auth_exec(struct ast_channel *chan, void *data)
}
}
strncpy ( password , data , sizeof ( password ) - 1 ) ;
opts = strchr ( password , ' | ' ) ;
if ( opts ) {
* opts = 0 ;
opts + + ;
} else
opts = " " ;
if ( strchr ( opts , ' j ' ) )
jump = 1 ;
argcopy = ast_strdupa ( data ) ;
if ( ! argcopy ) {
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
AST_STANDARD_APP_ARGS ( arglist , argcopy ) ;
if ( ! ast_strlen_zero ( arglist . options ) ) {
ast_app_parse_options ( auth_app_options , & flags , NULL , arglist . options ) ;
}
if ( ! ast_strlen_zero ( arglist . maxdigits ) ) {
maxdigits = atoi ( arglist . maxdigits ) ;
if ( ( maxdigits < 1 ) | | ( maxdigits > sizeof ( passwd ) - 2 ) )
maxdigits = sizeof ( passwd ) - 2 ;
} else {
maxdigits = sizeof ( passwd ) - 2 ;
}
/* Start asking for password */
prompt = " agent-pass " ;
for ( retries = 0 ; retries < 3 ; retries + + ) {
res = ast_app_getdata ( chan , prompt , passwd , sizeof ( passwd ) - 2 , 0 ) ;
res = ast_app_getdata ( chan , prompt , passwd , maxdigits , 0 ) ;
if ( res < 0 )
break ;
res = 0 ;
if ( password [ 0 ] = = ' / ' ) {
if ( strchr ( opts , ' d ' ) ) {
if ( arglist. password[ 0 ] = = ' / ' ) {
if ( ast_test_flag( & flags , OPT_DATABASE ) ) {
char tmp [ 256 ] ;
/* Compare against a database key */
if ( ! ast_db_get ( password + 1 , passwd , tmp , sizeof ( tmp ) ) ) {
if ( ! ast_db_get ( arglist. password + 1 , passwd , tmp , sizeof ( tmp ) ) ) {
/* It's a good password */
if ( strchr( opts , ' r ' ) ) {
ast_db_del ( password + 1 , passwd ) ;
if ( ast_test_flag( & flags , OPT_REMOVE ) ) {
ast_db_del ( arglist. password + 1 , passwd ) ;
}
break ;
}
} else {
/* Compare against a file */
FILE * f ;
f = fopen ( password, " r " ) ;
f = fopen ( arglist. password, " r " ) ;
if ( f ) {
char buf [ 256 ] = " " ;
char md5passwd [ 33 ] = " " ;
@ -141,7 +180,7 @@ static int auth_exec(struct ast_channel *chan, void *data)
fgets ( buf , sizeof ( buf ) , f ) ;
if ( ! feof ( f ) & & ! ast_strlen_zero ( buf ) ) {
buf [ strlen ( buf ) - 1 ] = ' \0 ' ;
if ( strchr( opts , ' m ' ) ) {
if ( ast_test_flag( & flags , OPT_MULTIPLE ) ) {
md5secret = strchr ( buf , ' : ' ) ;
if ( md5secret = = NULL )
continue ;
@ -149,13 +188,13 @@ static int auth_exec(struct ast_channel *chan, void *data)
md5secret + + ;
ast_md5_hash ( md5passwd , passwd ) ;
if ( ! strcmp ( md5passwd , md5secret ) ) {
if ( strchr( opts , ' a ' ) )
if ( ast_test_flag( & flags , OPT_ACCOUNT ) )
ast_cdr_setaccount ( chan , buf ) ;
break ;
}
} else {
if ( ! strcmp ( passwd , buf ) ) {
if ( strchr( opts , ' a ' ) )
if ( ast_test_flag( & flags , OPT_ACCOUNT ) )
ast_cdr_setaccount ( chan , buf ) ;
break ;
}
@ -164,7 +203,7 @@ static int auth_exec(struct ast_channel *chan, void *data)
}
fclose ( f ) ;
if ( ! ast_strlen_zero ( buf ) ) {
if ( strchr( opts , ' m ' ) ) {
if ( ast_test_flag( & flags , OPT_MULTIPLE ) ) {
if ( md5secret & & ! strcmp ( md5passwd , md5secret ) )
break ;
} else {
@ -173,23 +212,23 @@ static int auth_exec(struct ast_channel *chan, void *data)
}
}
} else
ast_log ( LOG_WARNING , " Unable to open file '%s' for authentication: %s \n " , password, strerror ( errno ) ) ;
ast_log ( LOG_WARNING , " Unable to open file '%s' for authentication: %s \n " , arglist. password, strerror ( errno ) ) ;
}
} else {
/* Compare against a fixed password */
if ( ! strcmp ( passwd , password) )
if ( ! strcmp ( passwd , arglist. password) )
break ;
}
prompt = " auth-incorrect " ;
}
if ( ( retries < 3 ) & & ! res ) {
if ( strchr( opts , ' a ' ) & & ! strchr ( opts , ' m ' ) )
if ( ast_test_flag( & flags , OPT_ACCOUNT ) & & ! ast_test_flag ( & flags , OPT_MULTIPLE ) )
ast_cdr_setaccount ( chan , passwd ) ;
res = ast_streamfile ( chan , " auth-thankyou " , chan - > language ) ;
if ( ! res )
res = ast_waitstream ( chan , " " ) ;
} else {
if ( jump & & ast_goto_if_exists ( chan , chan - > context , chan - > exten , chan - > priority + 101 ) ) {
if ( ast_test_flag ( & flags , OPT_JUMP ) & & ast_goto_if_exists ( chan , chan - > context , chan - > exten , chan - > priority + 101 ) ) {
res = 0 ;
} else {
if ( ! ast_streamfile ( chan , " vm-goodbye " , chan - > language ) )