Fri Jun 19 12:09:24 2009

Asterisk developer's documentation


app_authenticate.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Execute arbitrary authenticate commands
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \ingroup applications
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153710 $")
00031 
00032 #include "asterisk/lock.h"
00033 #include "asterisk/file.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/pbx.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/app.h"
00038 #include "asterisk/astdb.h"
00039 #include "asterisk/utils.h"
00040 
00041 enum {
00042    OPT_ACCOUNT = (1 << 0),
00043    OPT_DATABASE = (1 << 1),
00044    OPT_MULTIPLE = (1 << 3),
00045    OPT_REMOVE = (1 << 4),
00046 } auth_option_flags;
00047 
00048 AST_APP_OPTIONS(auth_app_options, {
00049    AST_APP_OPTION('a', OPT_ACCOUNT),
00050    AST_APP_OPTION('d', OPT_DATABASE),
00051    AST_APP_OPTION('m', OPT_MULTIPLE),
00052    AST_APP_OPTION('r', OPT_REMOVE),
00053 });
00054 
00055 
00056 static char *app = "Authenticate";
00057 
00058 static char *synopsis = "Authenticate a user";
00059 
00060 static char *descrip =
00061 "  Authenticate(password[,options[,maxdigits]]): This application asks the caller\n"
00062 "to enter a given password in order to continue dialplan execution. If the password\n"
00063 "begins with the '/' character, it is interpreted as a file which contains a list of\n"
00064 "valid passwords, listed 1 password per line in the file.\n"
00065 "  When using a database key, the value associated with the key can be anything.\n"
00066 "Users have three attempts to authenticate before the channel is hung up.\n"
00067 "  Options:\n"
00068 "     a - Set the channels' account code to the password that is entered\n"
00069 "     d - Interpret the given path as database key, not a literal file\n"
00070 "     m - Interpret the given path as a file which contains a list of account\n"
00071 "         codes and password hashes delimited with ':', listed one per line in\n"
00072 "         the file. When one of the passwords is matched, the channel will have\n"
00073 "         its account code set to the corresponding account code in the file.\n"
00074 "     r - Remove the database key upon successful entry (valid with 'd' only)\n"
00075 "     maxdigits  - maximum acceptable number of digits. Stops reading after\n"
00076 "         maxdigits have been entered (without requiring the user to\n"
00077 "         press the '#' key).\n"
00078 "         Defaults to 0 - no limit - wait for the user press the '#' key.\n"
00079 ;
00080 
00081 static int auth_exec(struct ast_channel *chan, void *data)
00082 {
00083    int res = 0, retries, maxdigits;
00084    char passwd[256], *prompt = "agent-pass", *argcopy = NULL;
00085    struct ast_flags flags = {0};
00086 
00087    AST_DECLARE_APP_ARGS(arglist,
00088       AST_APP_ARG(password);
00089       AST_APP_ARG(options);
00090       AST_APP_ARG(maxdigits);
00091    );
00092 
00093    if (ast_strlen_zero(data)) {
00094       ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
00095       return -1;
00096    }
00097 
00098    if (chan->_state != AST_STATE_UP) {
00099       if ((res = ast_answer(chan)))
00100          return -1;
00101    }
00102 
00103    argcopy = ast_strdupa(data);
00104 
00105    AST_STANDARD_APP_ARGS(arglist, argcopy);
00106 
00107    if (!ast_strlen_zero(arglist.options))
00108       ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
00109 
00110    if (!ast_strlen_zero(arglist.maxdigits)) {
00111       maxdigits = atoi(arglist.maxdigits);
00112       if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
00113          maxdigits = sizeof(passwd) - 2;
00114    } else {
00115       maxdigits = sizeof(passwd) - 2;
00116    }
00117 
00118    /* Start asking for password */
00119    for (retries = 0; retries < 3; retries++) {
00120       if ((res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0)) < 0)
00121          break;
00122 
00123       res = 0;
00124 
00125       if (arglist.password[0] != '/') {
00126          /* Compare against a fixed password */
00127          if (!strcmp(passwd, arglist.password))
00128             break;
00129       } else if (ast_test_flag(&flags,OPT_DATABASE)) {
00130          char tmp[256];
00131          /* Compare against a database key */
00132          if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
00133             /* It's a good password */
00134             if (ast_test_flag(&flags,OPT_REMOVE))
00135                ast_db_del(arglist.password + 1, passwd);
00136             break;
00137          }
00138       } else {
00139          /* Compare against a file */
00140          FILE *f;
00141          char buf[256] = "", md5passwd[33] = "", *md5secret = NULL;
00142 
00143          if (!(f = fopen(arglist.password, "r"))) {
00144             ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
00145             continue;
00146          }
00147 
00148          for (;;) {
00149             size_t len;
00150 
00151             if (feof(f))
00152                break;
00153 
00154             if (!fgets(buf, sizeof(buf), f)) {
00155                continue;
00156             }
00157 
00158             if (ast_strlen_zero(buf))
00159                continue;
00160 
00161             len = strlen(buf) - 1;
00162             if (buf[len] == '\n')
00163                buf[len] = '\0';
00164 
00165             if (ast_test_flag(&flags, OPT_MULTIPLE)) {
00166                md5secret = buf;
00167                strsep(&md5secret, ":");
00168                if (!md5secret)
00169                   continue;
00170                ast_md5_hash(md5passwd, passwd);
00171                if (!strcmp(md5passwd, md5secret)) {
00172                   if (ast_test_flag(&flags,OPT_ACCOUNT))
00173                      ast_cdr_setaccount(chan, buf);
00174                   break;
00175                }
00176             } else {
00177                if (!strcmp(passwd, buf)) {
00178                   if (ast_test_flag(&flags, OPT_ACCOUNT))
00179                      ast_cdr_setaccount(chan, buf);
00180                   break;
00181                }
00182             }
00183          }
00184 
00185          fclose(f);
00186 
00187          if (!ast_strlen_zero(buf)) {
00188             if (ast_test_flag(&flags, OPT_MULTIPLE)) {
00189                if (md5secret && !strcmp(md5passwd, md5secret))
00190                   break;
00191             } else {
00192                if (!strcmp(passwd, buf))
00193                   break;
00194             }
00195          }
00196       }
00197       prompt = "auth-incorrect";
00198    }
00199 
00200    if ((retries < 3) && !res) {
00201       if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
00202          ast_cdr_setaccount(chan, passwd);
00203       if (!(res = ast_streamfile(chan, "auth-thankyou", chan->language)))
00204          res = ast_waitstream(chan, "");
00205    } else {
00206       if (!ast_streamfile(chan, "vm-goodbye", chan->language))
00207          res = ast_waitstream(chan, "");
00208       res = -1;
00209    }
00210 
00211    return res;
00212 }
00213 
00214 static int unload_module(void)
00215 {
00216    return ast_unregister_application(app);
00217 }
00218 
00219 static int load_module(void)
00220 {
00221    if (ast_register_application(app, auth_exec, synopsis, descrip))
00222       return AST_MODULE_LOAD_FAILURE;
00223    return AST_MODULE_LOAD_SUCCESS;
00224 }
00225 
00226 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");

Generated on Fri Jun 19 12:09:24 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7