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