diff options
Diffstat (limited to 'trunk/apps/app_authenticate.c')
-rw-r--r-- | trunk/apps/app_authenticate.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/trunk/apps/app_authenticate.c b/trunk/apps/app_authenticate.c new file mode 100644 index 000000000..3a3e7582e --- /dev/null +++ b/trunk/apps/app_authenticate.c @@ -0,0 +1,212 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2005, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Execute arbitrary authenticate commands + * + * \author Mark Spencer <markster@digium.com> + * + * \ingroup applications + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/lock.h" +#include "asterisk/file.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/app.h" +#include "asterisk/astdb.h" +#include "asterisk/utils.h" + +enum { + OPT_ACCOUNT = (1 << 0), + OPT_DATABASE = (1 << 1), + 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('m', OPT_MULTIPLE), + AST_APP_OPTION('r', OPT_REMOVE), +}); + + +static char *app = "Authenticate"; + +static char *synopsis = "Authenticate a user"; + +static char *descrip = +" 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.\n" +" Options:\n" +" a - Set the channels' account code to the password that is entered\n" +" d - Interpret the given path as database key, not a literal file\n" +" m - Interpret the given path as a file which contains a list of account\n" +" codes and password hashes delimited with ':', listed one per line in\n" +" 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" +; + +static int auth_exec(struct ast_channel *chan, void *data) +{ + int res = 0, retries, maxdigits; + char passwd[256], *prompt = "agent-pass", *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"); + return -1; + } + + if (chan->_state != AST_STATE_UP) { + if ((res = ast_answer(chan))) + return -1; + } + + argcopy = ast_strdupa(data); + + 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 */ + for (retries = 0; retries < 3; retries++) { + if ((res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0)) < 0) + break; + res = 0; + if (arglist.password[0] == '/') { + if (ast_test_flag(&flags,OPT_DATABASE)) { + char tmp[256]; + /* Compare against a database key */ + if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) { + /* It's a good password */ + if (ast_test_flag(&flags,OPT_REMOVE)) + ast_db_del(arglist.password + 1, passwd); + break; + } + } else { + /* Compare against a file */ + FILE *f; + char buf[256] = "", md5passwd[33] = "", *md5secret = NULL; + + if (!(f = fopen(arglist.password, "r"))) { + ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno)); + continue; + } + + while (!feof(f)) { + fgets(buf, sizeof(buf), f); + if (!feof(f) && !ast_strlen_zero(buf)) { + buf[strlen(buf) - 1] = '\0'; + if (ast_test_flag(&flags,OPT_MULTIPLE)) { + md5secret = strchr(buf, ':'); + if (md5secret == NULL) + continue; + *md5secret = '\0'; + md5secret++; + ast_md5_hash(md5passwd, passwd); + if (!strcmp(md5passwd, md5secret)) { + if (ast_test_flag(&flags,OPT_ACCOUNT)) + ast_cdr_setaccount(chan, buf); + break; + } + } else { + if (!strcmp(passwd, buf)) { + if (ast_test_flag(&flags,OPT_ACCOUNT)) + ast_cdr_setaccount(chan, buf); + break; + } + } + } + } + fclose(f); + if (!ast_strlen_zero(buf)) { + if (ast_test_flag(&flags,OPT_MULTIPLE)) { + if (md5secret && !strcmp(md5passwd, md5secret)) + break; + } else { + if (!strcmp(passwd, buf)) + break; + } + } + } + } else { + /* Compare against a fixed password */ + if (!strcmp(passwd, arglist.password)) + break; + } + prompt = "auth-incorrect"; + } + if ((retries < 3) && !res) { + if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE)) + ast_cdr_setaccount(chan, passwd); + if (!(res = ast_streamfile(chan, "auth-thankyou", chan->language))) + res = ast_waitstream(chan, ""); + } else { + if (!ast_streamfile(chan, "vm-goodbye", chan->language)) + res = ast_waitstream(chan, ""); + res = -1; + } + + return res; +} + +static int unload_module(void) +{ + return ast_unregister_application(app); +} + +static int load_module(void) +{ + if (ast_register_application(app, auth_exec, synopsis, descrip)) + return AST_MODULE_LOAD_FAILURE; + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application"); |