00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00031
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <stdio.h>
00037
00038 #include "asterisk/lock.h"
00039 #include "asterisk/file.h"
00040 #include "asterisk/logger.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/astdb.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/options.h"
00048
00049 enum {
00050 OPT_ACCOUNT = (1 << 0),
00051 OPT_DATABASE = (1 << 1),
00052 OPT_JUMP = (1 << 2),
00053 OPT_MULTIPLE = (1 << 3),
00054 OPT_REMOVE = (1 << 4),
00055 } auth_option_flags;
00056
00057 AST_APP_OPTIONS(auth_app_options, {
00058 AST_APP_OPTION('a', OPT_ACCOUNT),
00059 AST_APP_OPTION('d', OPT_DATABASE),
00060 AST_APP_OPTION('j', OPT_JUMP),
00061 AST_APP_OPTION('m', OPT_MULTIPLE),
00062 AST_APP_OPTION('r', OPT_REMOVE),
00063 });
00064
00065
00066 static char *app = "Authenticate";
00067
00068 static char *synopsis = "Authenticate a user";
00069
00070 static char *descrip =
00071 " Authenticate(password[|options[|maxdigits]]): This application asks the caller\n"
00072 "to enter a given password in order to continue dialplan execution. If the password\n"
00073 "begins with the '/' character, it is interpreted as a file which contains a list of\n"
00074 "valid passwords, listed 1 password per line in the file.\n"
00075 " When using a database key, the value associated with the key can be anything.\n"
00076 "Users have three attempts to authenticate before the channel is hung up. If the\n"
00077 "passsword is invalid, the 'j' option is specified, and priority n+101 exists,\n"
00078 "dialplan execution will continnue at this location.\n"
00079 " Options:\n"
00080 " a - Set the channels' account code to the password that is entered\n"
00081 " d - Interpret the given path as database key, not a literal file\n"
00082 " j - Support jumping to n+101 if authentication fails\n"
00083 " m - Interpret the given path as a file which contains a list of account\n"
00084 " codes and password hashes delimited with ':', listed one per line in\n"
00085 " the file. When one of the passwords is matched, the channel will have\n"
00086 " its account code set to the corresponding account code in the file.\n"
00087 " r - Remove the database key upon successful entry (valid with 'd' only)\n"
00088 " maxdigits - maximum acceptable number of digits. Stops reading after\n"
00089 " maxdigits have been entered (without requiring the user to\n"
00090 " press the '#' key).\n"
00091 " Defaults to 0 - no limit - wait for the user press the '#' key.\n"
00092 ;
00093
00094 static int auth_exec(struct ast_channel *chan, void *data)
00095 {
00096 int res=0;
00097 int retries;
00098 struct ast_module_user *u;
00099 char passwd[256];
00100 char *prompt;
00101 int maxdigits;
00102 char *argcopy =NULL;
00103 struct ast_flags flags = {0};
00104
00105 AST_DECLARE_APP_ARGS(arglist,
00106 AST_APP_ARG(password);
00107 AST_APP_ARG(options);
00108 AST_APP_ARG(maxdigits);
00109 );
00110
00111 if (ast_strlen_zero(data)) {
00112 ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
00113 return -1;
00114 }
00115
00116 u = ast_module_user_add(chan);
00117
00118 if (chan->_state != AST_STATE_UP) {
00119 res = ast_answer(chan);
00120 if (res) {
00121 ast_module_user_remove(u);
00122 return -1;
00123 }
00124 }
00125
00126 argcopy = ast_strdupa(data);
00127
00128 AST_STANDARD_APP_ARGS(arglist,argcopy);
00129
00130 if (!ast_strlen_zero(arglist.options)) {
00131 ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
00132 }
00133
00134 if (!ast_strlen_zero(arglist.maxdigits)) {
00135 maxdigits = atoi(arglist.maxdigits);
00136 if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
00137 maxdigits = sizeof(passwd) - 2;
00138 } else {
00139 maxdigits = sizeof(passwd) - 2;
00140 }
00141
00142
00143 prompt = "agent-pass";
00144 for (retries = 0; retries < 3; retries++) {
00145 res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0);
00146 if (res < 0)
00147 break;
00148 res = 0;
00149 if (arglist.password[0] == '/') {
00150 if (ast_test_flag(&flags,OPT_DATABASE)) {
00151 char tmp[256];
00152
00153 if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
00154
00155 if (ast_test_flag(&flags,OPT_REMOVE)) {
00156 ast_db_del(arglist.password + 1, passwd);
00157 }
00158 break;
00159 }
00160 } else {
00161
00162 FILE *f;
00163 f = fopen(arglist.password, "r");
00164 if (f) {
00165 char buf[256] = "";
00166 char md5passwd[33] = "";
00167 char *md5secret = NULL;
00168
00169 while (!feof(f)) {
00170 fgets(buf, sizeof(buf), f);
00171 if (!ast_strlen_zero(buf)) {
00172 size_t len = strlen(buf);
00173 if (buf[len - 1] == '\n')
00174 buf[len - 1] = '\0';
00175 if (ast_test_flag(&flags,OPT_MULTIPLE)) {
00176 md5secret = strchr(buf, ':');
00177 if (md5secret == NULL)
00178 continue;
00179 *md5secret = '\0';
00180 md5secret++;
00181 ast_md5_hash(md5passwd, passwd);
00182 if (!strcmp(md5passwd, md5secret)) {
00183 if (ast_test_flag(&flags,OPT_ACCOUNT))
00184 ast_cdr_setaccount(chan, buf);
00185 break;
00186 }
00187 } else {
00188 if (!strcmp(passwd, buf)) {
00189 if (ast_test_flag(&flags,OPT_ACCOUNT))
00190 ast_cdr_setaccount(chan, buf);
00191 break;
00192 }
00193 }
00194 }
00195 }
00196 fclose(f);
00197 if (!ast_strlen_zero(buf)) {
00198 if (ast_test_flag(&flags,OPT_MULTIPLE)) {
00199 if (md5secret && !strcmp(md5passwd, md5secret))
00200 break;
00201 } else {
00202 if (!strcmp(passwd, buf))
00203 break;
00204 }
00205 }
00206 } else
00207 ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
00208 }
00209 } else {
00210
00211 if (!strcmp(passwd, arglist.password))
00212 break;
00213 }
00214 prompt="auth-incorrect";
00215 }
00216 if ((retries < 3) && !res) {
00217 if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
00218 ast_cdr_setaccount(chan, passwd);
00219 res = ast_streamfile(chan, "auth-thankyou", chan->language);
00220 if (!res)
00221 res = ast_waitstream(chan, "");
00222 } else {
00223 if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0) {
00224 res = 0;
00225 } else {
00226 if (!ast_streamfile(chan, "vm-goodbye", chan->language))
00227 res = ast_waitstream(chan, "");
00228 res = -1;
00229 }
00230 }
00231 ast_module_user_remove(u);
00232 return res;
00233 }
00234
00235 static int unload_module(void)
00236 {
00237 int res;
00238
00239 ast_module_user_hangup_all();
00240
00241 res = ast_unregister_application(app);
00242
00243
00244 return res;
00245 }
00246
00247 static int load_module(void)
00248 {
00249 return ast_register_application(app, auth_exec, synopsis, descrip);
00250 }
00251
00252 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");