Added feature from bug #5053, allowing for
authorMatt O'Gorman <mogorman@digium.com>
Thu, 5 Jan 2006 21:47:44 +0000 (21:47 +0000)
committerMatt O'Gorman <mogorman@digium.com>
Thu, 5 Jan 2006 21:47:44 +0000 (21:47 +0000)
app_authenticate to set a max number of digits
also implemented the new argument and option
parsing code.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7822 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_authenticate.c

index 274aec4..b7678a0 100644 (file)
@@ -44,6 +44,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/astdb.h"
 #include "asterisk/utils.h"
+#include "asterisk/options.h"
+
+enum {
+       OPT_ACCOUNT = (1 << 0),
+       OPT_DATABASE = (1 << 1),
+       OPT_JUMP = (1 << 2),
+       OPT_MULTIPLE = (1 << 3),
+       OPT_REMOVE = (1 << 4),
+} auth_option_flags;
+
+AST_APP_OPTIONS(auth_app_options, {
+       AST_APP_OPTION('a', OPT_ACCOUNT),
+       AST_APP_OPTION('d', OPT_DATABASE),
+       AST_APP_OPTION('j', OPT_JUMP),
+       AST_APP_OPTION('m', OPT_MULTIPLE),
+       AST_APP_OPTION('r', OPT_REMOVE),
+});
 
 static char *tdesc = "Authentication Application";
 
@@ -52,9 +69,9 @@ static char *app = "Authenticate";
 static char *synopsis = "Authenticate a user";
 
 static char *descrip =
-"  Authenticate(password[|options]): This application asks the caller to enter a\n"
-"given password in order to continue dialplan execution. If the password begins\n"
-"with the '/' character, it is interpreted as a file which contains a list of\n"
+"  Authenticate(password[|options[|maxdigits]]): This application asks the caller\n"
+"to enter a given password in order to continue dialplan execution. If the password\n"
+"begins with the '/' character, it is interpreted as a file which contains a list of\n"
 "valid passwords, listed 1 password per line in the file.\n"
 "  When using a database key, the value associated with the key can be anything.\n"
 "Users have three attempts to authenticate before the channel is hung up. If the\n"
@@ -69,6 +86,10 @@ static char *descrip =
 "         the file. When one of the passwords is matched, the channel will have\n"
 "         its account code set to the corresponding account code in the file.\n"
 "     r - Remove the database key upon successful entry (valid with 'd' only)\n"
+"     maxdigits  - maximum acceptable number of digits. Stops reading after\n"
+"         maxdigits have been entered (without requiring the user to\n"
+"         press the '#' key).\n"
+"         Defaults to 0 - no limit - wait for the user press the '#' key.\n"
 ;
 
 STANDARD_LOCAL_USER;
@@ -78,13 +99,19 @@ LOCAL_USER_DECL;
 static int auth_exec(struct ast_channel *chan, void *data)
 {
        int res=0;
-       int jump = 0;
        int retries;
        struct localuser *u;
-       char password[256]="";
        char passwd[256];
-       char *opts;
        char *prompt;
+       int maxdigits;
+       char *argcopy =NULL;
+       struct ast_flags flags = {0};
+
+       AST_DECLARE_APP_ARGS(arglist,
+               AST_APP_ARG(password);
+               AST_APP_ARG(options);
+               AST_APP_ARG(maxdigits);
+       );
        
        if (ast_strlen_zero(data)) {
                ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
@@ -101,37 +128,49 @@ static int auth_exec(struct ast_channel *chan, void *data)
                }
        }
        
-       strncpy(password, data, sizeof(password) - 1);
-       opts=strchr(password, '|');
-       if (opts) {
-               *opts = 0;
-               opts++;
-       } else
-               opts = "";
-       if (strchr(opts, 'j'))
-               jump = 1;
+       argcopy = ast_strdupa(data);
+       if (!argcopy) {
+               ast_log(LOG_ERROR, "Out of memory!\n");
+               LOCAL_USER_REMOVE(u);
+               return -1;
+       }
+
+       AST_STANDARD_APP_ARGS(arglist,argcopy);
+       
+       if (!ast_strlen_zero(arglist.options)) {
+               ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
+       }
+
+       if (!ast_strlen_zero(arglist.maxdigits)) {
+               maxdigits = atoi(arglist.maxdigits);
+               if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
+                       maxdigits = sizeof(passwd) - 2;
+       } else {
+               maxdigits = sizeof(passwd) - 2;
+       }
+
        /* Start asking for password */
        prompt = "agent-pass";
        for (retries = 0; retries < 3; retries++) {
-               res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
+               res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0);
                if (res < 0)
                        break;
                res = 0;
-               if (password[0] == '/') {
-                       if (strchr(opts, 'd')) {
+               if (arglist.password[0] == '/') {
+                       if (ast_test_flag(&flags,OPT_DATABASE)) {
                                char tmp[256];
                                /* Compare against a database key */
-                               if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
+                               if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
                                        /* It's a good password */
-                                       if (strchr(opts, 'r')) {
-                                               ast_db_del(password + 1, passwd);
+                                       if (ast_test_flag(&flags,OPT_REMOVE)) {
+                                               ast_db_del(arglist.password + 1, passwd);
                                        }
                                        break;
                                }
                        } else {
                                /* Compare against a file */
                                FILE *f;
-                               f = fopen(password, "r");
+                               f = fopen(arglist.password, "r");
                                if (f) {
                                        char buf[256] = "";
                                        char md5passwd[33] = "";
@@ -141,7 +180,7 @@ static int auth_exec(struct ast_channel *chan, void *data)
                                                fgets(buf, sizeof(buf), f);
                                                if (!feof(f) && !ast_strlen_zero(buf)) {
                                                        buf[strlen(buf) - 1] = '\0';
-                                                       if (strchr(opts, 'm')) {
+                                                       if (ast_test_flag(&flags,OPT_MULTIPLE)) {
                                                                md5secret = strchr(buf, ':');
                                                                if (md5secret == NULL)
                                                                        continue;
@@ -149,13 +188,13 @@ static int auth_exec(struct ast_channel *chan, void *data)
                                                                md5secret++;
                                                                ast_md5_hash(md5passwd, passwd);
                                                                if (!strcmp(md5passwd, md5secret)) {
-                                                                       if (strchr(opts, 'a'))
+                                                                       if (ast_test_flag(&flags,OPT_ACCOUNT))
                                                                                ast_cdr_setaccount(chan, buf);
                                                                        break;
                                                                }
                                                        } else {
                                                                if (!strcmp(passwd, buf)) {
-                                                                       if (strchr(opts, 'a'))
+                                                                       if (ast_test_flag(&flags,OPT_ACCOUNT))
                                                                                ast_cdr_setaccount(chan, buf);
                                                                        break;
                                                                }
@@ -164,7 +203,7 @@ static int auth_exec(struct ast_channel *chan, void *data)
                                        }
                                        fclose(f);
                                        if (!ast_strlen_zero(buf)) {
-                                               if (strchr(opts, 'm')) {
+                                               if (ast_test_flag(&flags,OPT_MULTIPLE)) {
                                                        if (md5secret && !strcmp(md5passwd, md5secret))
                                                                break;
                                                } else {
@@ -173,23 +212,23 @@ static int auth_exec(struct ast_channel *chan, void *data)
                                                }
                                        }
                                } else 
-                                       ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
+                                       ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
                        }
                } else {
                        /* Compare against a fixed password */
-                       if (!strcmp(passwd, password)) 
+                       if (!strcmp(passwd, arglist.password)) 
                                break;
                }
                prompt="auth-incorrect";
        }
        if ((retries < 3) && !res) {
-               if (strchr(opts, 'a') && !strchr(opts, 'm')) 
+               if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE)) 
                        ast_cdr_setaccount(chan, passwd);
                res = ast_streamfile(chan, "auth-thankyou", chan->language);
                if (!res)
                        res = ast_waitstream(chan, "");
        } else {
-               if (jump && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
+               if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
                        res = 0;
                } else {
                        if (!ast_streamfile(chan, "vm-goodbye", chan->language))