2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Execute arbitrary authenticate commands
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include "asterisk/lock.h"
33 #include "asterisk/file.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/app.h"
38 #include "asterisk/astdb.h"
39 #include "asterisk/utils.h"
42 OPT_ACCOUNT = (1 << 0),
43 OPT_DATABASE = (1 << 1),
44 OPT_MULTIPLE = (1 << 3),
45 OPT_REMOVE = (1 << 4),
48 AST_APP_OPTIONS(auth_app_options, {
49 AST_APP_OPTION('a', OPT_ACCOUNT),
50 AST_APP_OPTION('d', OPT_DATABASE),
51 AST_APP_OPTION('m', OPT_MULTIPLE),
52 AST_APP_OPTION('r', OPT_REMOVE),
56 static const char app[] = "Authenticate";
58 <application name="Authenticate" language="en_US">
63 <parameter name="password" required="true">
64 <para>Password the user should know</para>
66 <parameter name="options" required="false">
69 <para>Set the channels' account code to the password that is entered</para>
72 <para>Interpret the given path as database key, not a literal file</para>
75 <para>Interpret the given path as a file which contains a list of account
76 codes and password hashes delimited with <literal>:</literal>, listed one per line in
77 the file. When one of the passwords is matched, the channel will have
78 its account code set to the corresponding account code in the file.</para>
81 <para>Remove the database key upon successful entry (valid with <literal>d</literal> only)</para>
85 <parameter name="maxdigits" required="false">
86 <para>maximum acceptable number of digits. Stops reading after
87 maxdigits have been entered (without requiring the user to press the <literal>#</literal> key).
88 Defaults to 0 - no limit - wait for the user press the <literal>#</literal> key.</para>
90 <parameter name="prompt" required="false">
91 <para>Override the agent-pass prompt file.</para>
95 <para>This application asks the caller to enter a given password in order to continue dialplan execution.</para>
96 <para>If the password begins with the <literal>/</literal> character,
97 it is interpreted as a file which contains a list of valid passwords, listed 1 password per line in the file.</para>
98 <para>When using a database key, the value associated with the key can be anything.</para>
99 <para>Users have three attempts to authenticate before the channel is hung up.</para>
102 <ref type="application">VMAuthenticate</ref>
103 <ref type="application">DISA</ref>
108 static int auth_exec(struct ast_channel *chan, const char *data)
110 int res = 0, retries, maxdigits;
111 char passwd[256], *prompt = "agent-pass", *argcopy = NULL;
112 struct ast_flags flags = {0};
114 AST_DECLARE_APP_ARGS(arglist,
115 AST_APP_ARG(password);
116 AST_APP_ARG(options);
117 AST_APP_ARG(maxdigits);
121 if (ast_strlen_zero(data)) {
122 ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
126 if (chan->_state != AST_STATE_UP) {
127 if ((res = ast_answer(chan)))
131 argcopy = ast_strdupa(data);
133 AST_STANDARD_APP_ARGS(arglist, argcopy);
135 if (!ast_strlen_zero(arglist.options))
136 ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
138 if (!ast_strlen_zero(arglist.maxdigits)) {
139 maxdigits = atoi(arglist.maxdigits);
140 if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
141 maxdigits = sizeof(passwd) - 2;
143 maxdigits = sizeof(passwd) - 2;
146 if (!ast_strlen_zero(arglist.prompt)) {
147 prompt = arglist.prompt;
149 prompt = "agent-pass";
152 /* Start asking for password */
153 for (retries = 0; retries < 3; retries++) {
154 if ((res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0)) < 0)
159 if (arglist.password[0] != '/') {
160 /* Compare against a fixed password */
161 if (!strcmp(passwd, arglist.password))
163 } else if (ast_test_flag(&flags,OPT_DATABASE)) {
165 /* Compare against a database key */
166 if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
167 /* It's a good password */
168 if (ast_test_flag(&flags,OPT_REMOVE))
169 ast_db_del(arglist.password + 1, passwd);
173 /* Compare against a file */
175 char buf[256] = "", md5passwd[33] = "", *md5secret = NULL;
177 if (!(f = fopen(arglist.password, "r"))) {
178 ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
188 if (!fgets(buf, sizeof(buf), f)) {
192 if (ast_strlen_zero(buf))
195 len = strlen(buf) - 1;
196 if (buf[len] == '\n')
199 if (ast_test_flag(&flags, OPT_MULTIPLE)) {
201 strsep(&md5secret, ":");
204 ast_md5_hash(md5passwd, passwd);
205 if (!strcmp(md5passwd, md5secret)) {
206 if (ast_test_flag(&flags,OPT_ACCOUNT))
207 ast_cdr_setaccount(chan, buf);
211 if (!strcmp(passwd, buf)) {
212 if (ast_test_flag(&flags, OPT_ACCOUNT))
213 ast_cdr_setaccount(chan, buf);
221 if (!ast_strlen_zero(buf)) {
222 if (ast_test_flag(&flags, OPT_MULTIPLE)) {
223 if (md5secret && !strcmp(md5passwd, md5secret))
226 if (!strcmp(passwd, buf))
231 prompt = "auth-incorrect";
234 if ((retries < 3) && !res) {
235 if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
236 ast_cdr_setaccount(chan, passwd);
237 if (!(res = ast_streamfile(chan, "auth-thankyou", chan->language)))
238 res = ast_waitstream(chan, "");
240 if (!ast_streamfile(chan, "vm-goodbye", chan->language))
241 res = ast_waitstream(chan, "");
248 static int unload_module(void)
250 return ast_unregister_application(app);
253 static int load_module(void)
255 if (ast_register_application_xml(app, auth_exec))
256 return AST_MODULE_LOAD_FAILURE;
257 return AST_MODULE_LOAD_SUCCESS;
260 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");