Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:47 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  * \brief Execute arbitrary authenticate commands
    00021  *
    00022  * \ingroup applications
    00023  */
    00024
    00025 #include <stdlib.h>
    00026 #include <unistd.h>
    00027 #include <string.h>
    00028 #include <errno.h>
    00029 #include <stdio.h>
    00030
    00031 #include "asterisk.h"
    00032
    00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 42421 $")
    00034
    00035 #include "asterisk/lock.h"
    00036 #include "asterisk/file.h"
    00037 #include "asterisk/logger.h"
    00038 #include "asterisk/channel.h"
    00039 #include "asterisk/pbx.h"
    00040 #include "asterisk/module.h"
    00041 #include "asterisk/app.h"
    00042 #include "asterisk/astdb.h"
    00043 #include "asterisk/utils.h"
    00044
    00045 static char *tdesc = "Authentication Application";
    00046
    00047 static char *app = "Authenticate";
    00048
    00049 static char *synopsis = "Authenticate a user";
    00050
    00051 static char *descrip =
    00052 "  Authenticate(password[|options]): This application asks the caller to enter a\n"
    00053 "given password in order to continue dialplan execution. If the password begins\n"
    00054 "with the '/' character, it is interpreted as a file which contains a list of\n"
    00055 "valid passwords, listed 1 password per line in the file.\n"
    00056 "  When using a database key, the value associated with the key can be anything.\n"
    00057 "Users have three attempts to authenticate before the channel is hung up. If the\n"
    00058 "passsword is invalid, the 'j' option is specified, and priority n+101 exists,\n"
    00059 "dialplan execution will continnue at this location.\n"
    00060 "  Options:\n"
    00061 "     a - Set the channels' account code to the password that is entered\n"
    00062 "     d - Interpret the given path as database key, not a literal file\n"
    00063 "     j - Support jumping to n+101 if authentication fails\n"
    00064 "     m - Interpret the given path as a file which contains a list of account\n"
    00065 "         codes and password hashes delimited with ':', listed one per line in\n"
    00066 "         the file. When one of the passwords is matched, the channel will have\n"
    00067 "         its account code set to the corresponding account code in the file.\n"
    00068 "     r - Remove the database key upon successful entry (valid with 'd' only)\n"
    00069 ;
    00070
    00071 STANDARD_LOCAL_USER;
    00072
    00073 LOCAL_USER_DECL;
    00074
    00075 static int auth_exec(struct ast_channel *chan, void *data)
    00076 {
    00077    int res=0;
    00078    int jump = 0;
    00079    int retries;
    00080    struct localuser *u;
    00081    char password[256]="";
    00082    char passwd[256];
    00083    char *opts;
    00084    char *prompt;
    00085
    00086    if (ast_strlen_zero(data)) {
    00087       ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
    00088       return -1;
    00089    }
    00090
    00091    LOCAL_USER_ADD(u);
    00092
    00093    if (chan->_state != AST_STATE_UP) {
    00094       res = ast_answer(chan);
    00095       if (res) {
    00096          LOCAL_USER_REMOVE(u);
    00097          return -1;
    00098       }
    00099    }
    00100
    00101    strncpy(password, data, sizeof(password) - 1);
    00102    opts=strchr(password, '|');
    00103    if (opts) {
    00104       *opts = 0;
    00105       opts++;
    00106    } else
    00107       opts = "";
    00108    if (strchr(opts, 'j'))
    00109       jump = 1;
    00110    /* Start asking for password */
    00111    prompt = "agent-pass";
    00112    for (retries = 0; retries < 3; retries++) {
    00113       res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
    00114       if (res < 0)
    00115          break;
    00116       res = 0;
    00117       if (password[0] == '/') {
    00118          if (strchr(opts, 'd')) {
    00119             char tmp[256];
    00120             /* Compare against a database key */
    00121             if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
    00122                /* It's a good password */
    00123                if (strchr(opts, 'r')) {
    00124                   ast_db_del(password + 1, passwd);
    00125                }
    00126                break;
    00127             }
    00128          } else {
    00129             /* Compare against a file */
    00130             FILE *f;
    00131             f = fopen(password, "r");
    00132             if (f) {
    00133                char buf[256] = "";
    00134                char md5passwd[33] = "";
    00135                char *md5secret = NULL;
    00136
    00137                while (!feof(f)) {
    00138                   fgets(buf, sizeof(buf), f);
    00139                   if (!feof(f) && !ast_strlen_zero(buf)) {
    00140                      buf[strlen(buf) - 1] = '\0';
    00141                      if (strchr(opts, 'm')) {
    00142                         md5secret = strchr(buf, ':');
    00143                         if (md5secret == NULL)
    00144                            continue;
    00145                         *md5secret = '\0';
    00146                         md5secret++;
    00147                         ast_md5_hash(md5passwd, passwd);
    00148                         if (!strcmp(md5passwd, md5secret)) {
    00149                            if (strchr(opts, 'a'))
    00150                               ast_cdr_setaccount(chan, buf);
    00151                            break;
    00152                         }
    00153                      } else {
    00154                         if (!strcmp(passwd, buf)) {
    00155                            if (strchr(opts, 'a'))
    00156                               ast_cdr_setaccount(chan, buf);
    00157                            break;
    00158                         }
    00159                      }
    00160                   }
    00161                }
    00162                fclose(f);
    00163                if (!ast_strlen_zero(buf)) {
    00164                   if (strchr(opts, 'm')) {
    00165                      if (md5secret && !strcmp(md5passwd, md5secret))
    00166                         break;
    00167                   } else {
    00168                      if (!strcmp(passwd, buf))
    00169                         break;
    00170                   }
    00171                }
    00172             } else
    00173                ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
    00174          }
    00175       } else {
    00176          /* Compare against a fixed password */
    00177          if (!strcmp(passwd, password))
    00178             break;
    00179       }
    00180       prompt="auth-incorrect";
    00181    }
    00182    if ((retries < 3) && !res) {
    00183       if (strchr(opts, 'a') && !strchr(opts, 'm'))
    00184          ast_cdr_setaccount(chan, passwd);
    00185       res = ast_streamfile(chan, "auth-thankyou", chan->language);
    00186       if (!res)
    00187          res = ast_waitstream(chan, "");
    00188    } else {
    00189       if (jump && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0) {
    00190          res = 0;
    00191       } else {
    00192          if (!ast_streamfile(chan, "vm-goodbye", chan->language))
    00193             res = ast_waitstream(chan, "");
    00194          res = -1;
    00195       }
    00196    }
    00197    LOCAL_USER_REMOVE(u);
    00198    return res;
    00199 }
    00200
    00201 int unload_module(void)
    00202 {
    00203    int res;
    00204
    00205    res = ast_unregister_application(app);
    00206
    00207    STANDARD_HANGUP_LOCALUSERS;
    00208
    00209    return res;
    00210 }
    00211
    00212 int load_module(void)
    00213 {
    00214    return ast_register_application(app, auth_exec, synopsis, descrip);
    00215 }
    00216
    00217 char *description(void)
    00218 {
    00219    return tdesc;
    00220 }
    00221
    00222 int usecount(void)
    00223 {
    00224    int res;
    00225    STANDARD_USECOUNT(res);
    00226    return res;
    00227 }
    00228
    00229 char *key()
    00230 {
    00231    return ASTERISK_GPL_KEY;
    00232 }