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