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