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$")
38 #include "asterisk/lock.h"
39 #include "asterisk/file.h"
40 #include "asterisk/logger.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/module.h"
44 #include "asterisk/app.h"
45 #include "asterisk/astdb.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/options.h"
50 OPT_ACCOUNT
= (1 << 0),
51 OPT_DATABASE
= (1 << 1),
53 OPT_MULTIPLE
= (1 << 3),
54 OPT_REMOVE
= (1 << 4),
57 AST_APP_OPTIONS(auth_app_options
, {
58 AST_APP_OPTION('a', OPT_ACCOUNT
),
59 AST_APP_OPTION('d', OPT_DATABASE
),
60 AST_APP_OPTION('j', OPT_JUMP
),
61 AST_APP_OPTION('m', OPT_MULTIPLE
),
62 AST_APP_OPTION('r', OPT_REMOVE
),
66 static char *app
= "Authenticate";
68 static char *synopsis
= "Authenticate a user";
70 static char *descrip
=
71 " Authenticate(password[|options[|maxdigits]]): This application asks the caller\n"
72 "to enter a given password in order to continue dialplan execution. If the password\n"
73 "begins with the '/' character, it is interpreted as a file which contains a list of\n"
74 "valid passwords, listed 1 password per line in the file.\n"
75 " When using a database key, the value associated with the key can be anything.\n"
76 "Users have three attempts to authenticate before the channel is hung up. If the\n"
77 "passsword is invalid, the 'j' option is specified, and priority n+101 exists,\n"
78 "dialplan execution will continnue at this location.\n"
80 " a - Set the channels' account code to the password that is entered\n"
81 " d - Interpret the given path as database key, not a literal file\n"
82 " j - Support jumping to n+101 if authentication fails\n"
83 " m - Interpret the given path as a file which contains a list of account\n"
84 " codes and password hashes delimited with ':', listed one per line in\n"
85 " the file. When one of the passwords is matched, the channel will have\n"
86 " its account code set to the corresponding account code in the file.\n"
87 " r - Remove the database key upon successful entry (valid with 'd' only)\n"
88 " maxdigits - maximum acceptable number of digits. Stops reading after\n"
89 " maxdigits have been entered (without requiring the user to\n"
90 " press the '#' key).\n"
91 " Defaults to 0 - no limit - wait for the user press the '#' key.\n"
94 static int auth_exec(struct ast_channel
*chan
, void *data
)
98 struct ast_module_user
*u
;
103 struct ast_flags flags
= {0};
105 AST_DECLARE_APP_ARGS(arglist
,
106 AST_APP_ARG(password
);
107 AST_APP_ARG(options
);
108 AST_APP_ARG(maxdigits
);
111 if (ast_strlen_zero(data
)) {
112 ast_log(LOG_WARNING
, "Authenticate requires an argument(password)\n");
116 u
= ast_module_user_add(chan
);
118 if (chan
->_state
!= AST_STATE_UP
) {
119 res
= ast_answer(chan
);
121 ast_module_user_remove(u
);
126 argcopy
= ast_strdupa(data
);
128 AST_STANDARD_APP_ARGS(arglist
,argcopy
);
130 if (!ast_strlen_zero(arglist
.options
)) {
131 ast_app_parse_options(auth_app_options
, &flags
, NULL
, arglist
.options
);
134 if (!ast_strlen_zero(arglist
.maxdigits
)) {
135 maxdigits
= atoi(arglist
.maxdigits
);
136 if ((maxdigits
<1) || (maxdigits
>sizeof(passwd
)-2))
137 maxdigits
= sizeof(passwd
) - 2;
139 maxdigits
= sizeof(passwd
) - 2;
142 /* Start asking for password */
143 prompt
= "agent-pass";
144 for (retries
= 0; retries
< 3; retries
++) {
145 res
= ast_app_getdata(chan
, prompt
, passwd
, maxdigits
, 0);
149 if (arglist
.password
[0] == '/') {
150 if (ast_test_flag(&flags
,OPT_DATABASE
)) {
152 /* Compare against a database key */
153 if (!ast_db_get(arglist
.password
+ 1, passwd
, tmp
, sizeof(tmp
))) {
154 /* It's a good password */
155 if (ast_test_flag(&flags
,OPT_REMOVE
)) {
156 ast_db_del(arglist
.password
+ 1, passwd
);
161 /* Compare against a file */
163 f
= fopen(arglist
.password
, "r");
166 char md5passwd
[33] = "";
167 char *md5secret
= NULL
;
170 fgets(buf
, sizeof(buf
), f
);
171 if (!feof(f
) && !ast_strlen_zero(buf
)) {
172 buf
[strlen(buf
) - 1] = '\0';
173 if (ast_test_flag(&flags
,OPT_MULTIPLE
)) {
174 md5secret
= strchr(buf
, ':');
175 if (md5secret
== NULL
)
179 ast_md5_hash(md5passwd
, passwd
);
180 if (!strcmp(md5passwd
, md5secret
)) {
181 if (ast_test_flag(&flags
,OPT_ACCOUNT
))
182 ast_cdr_setaccount(chan
, buf
);
186 if (!strcmp(passwd
, buf
)) {
187 if (ast_test_flag(&flags
,OPT_ACCOUNT
))
188 ast_cdr_setaccount(chan
, buf
);
195 if (!ast_strlen_zero(buf
)) {
196 if (ast_test_flag(&flags
,OPT_MULTIPLE
)) {
197 if (md5secret
&& !strcmp(md5passwd
, md5secret
))
200 if (!strcmp(passwd
, buf
))
205 ast_log(LOG_WARNING
, "Unable to open file '%s' for authentication: %s\n", arglist
.password
, strerror(errno
));
208 /* Compare against a fixed password */
209 if (!strcmp(passwd
, arglist
.password
))
212 prompt
="auth-incorrect";
214 if ((retries
< 3) && !res
) {
215 if (ast_test_flag(&flags
,OPT_ACCOUNT
) && !ast_test_flag(&flags
,OPT_MULTIPLE
))
216 ast_cdr_setaccount(chan
, passwd
);
217 res
= ast_streamfile(chan
, "auth-thankyou", chan
->language
);
219 res
= ast_waitstream(chan
, "");
221 if (ast_test_flag(&flags
,OPT_JUMP
) && ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101) == 0) {
224 if (!ast_streamfile(chan
, "vm-goodbye", chan
->language
))
225 res
= ast_waitstream(chan
, "");
229 ast_module_user_remove(u
);
233 static int unload_module(void)
237 ast_module_user_hangup_all();
239 res
= ast_unregister_application(app
);
245 static int load_module(void)
247 return ast_register_application(app
, auth_exec
, synopsis
, descrip
);
250 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Authentication Application");