Sat Aug 6 00:39:19 2011

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

Generated on Sat Aug 6 00:39:19 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7