Mon Mar 31 07:37:54 2008

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

Generated on Mon Mar 31 07:37:54 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1