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: 153337 $")
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 if (!fgets(buf, sizeof(buf), f)) {
00171 continue;
00172 }
00173 if (!ast_strlen_zero(buf)) {
00174 size_t len = strlen(buf);
00175 if (buf[len - 1] == '\n')
00176 buf[len - 1] = '\0';
00177 if (ast_test_flag(&flags,OPT_MULTIPLE)) {
00178 md5secret = strchr(buf, ':');
00179 if (md5secret == NULL)
00180 continue;
00181 *md5secret = '\0';
00182 md5secret++;
00183 ast_md5_hash(md5passwd, passwd);
00184 if (!strcmp(md5passwd, md5secret)) {
00185 if (ast_test_flag(&flags,OPT_ACCOUNT))
00186 ast_cdr_setaccount(chan, buf);
00187 break;
00188 }
00189 } else {
00190 if (!strcmp(passwd, buf)) {
00191 if (ast_test_flag(&flags,OPT_ACCOUNT))
00192 ast_cdr_setaccount(chan, buf);
00193 break;
00194 }
00195 }
00196 }
00197 }
00198 fclose(f);
00199 if (!ast_strlen_zero(buf)) {
00200 if (ast_test_flag(&flags,OPT_MULTIPLE)) {
00201 if (md5secret && !strcmp(md5passwd, md5secret))
00202 break;
00203 } else {
00204 if (!strcmp(passwd, buf))
00205 break;
00206 }
00207 }
00208 } else
00209 ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
00210 }
00211 } else {
00212
00213 if (!strcmp(passwd, arglist.password))
00214 break;
00215 }
00216 prompt="auth-incorrect";
00217 }
00218 if ((retries < 3) && !res) {
00219 if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
00220 ast_cdr_setaccount(chan, passwd);
00221 res = ast_streamfile(chan, "auth-thankyou", chan->language);
00222 if (!res)
00223 res = ast_waitstream(chan, "");
00224 } else {
00225 if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0) {
00226 res = 0;
00227 } else {
00228 if (!ast_streamfile(chan, "vm-goodbye", chan->language))
00229 res = ast_waitstream(chan, "");
00230 res = -1;
00231 }
00232 }
00233 ast_module_user_remove(u);
00234 return res;
00235 }
00236
00237 static int unload_module(void)
00238 {
00239 int res;
00240
00241 ast_module_user_hangup_all();
00242
00243 res = ast_unregister_application(app);
00244
00245
00246 return res;
00247 }
00248
00249 static int load_module(void)
00250 {
00251 return ast_register_application(app, auth_exec, synopsis, descrip);
00252 }
00253
00254 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");