Add support for authenticating against astdb and one time authentication
[asterisk/asterisk.git] / apps / app_authenticate.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Execute arbitrary authenticate commands
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/app.h>
21 #include <asterisk/astdb.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <pthread.h>
29
30
31 static char *tdesc = "Authentication Application";
32
33 static char *app = "Authenticate";
34
35 static char *synopsis = "Authenticate a user";
36
37 static char *descrip =
38 "  Authenticate(password[|options]): Requires a user to enter a"
39 "given password in order to continue execution.  If the\n"
40 "password begins with the '/' character, it is interpreted as\n"
41 "a file which contains a list of valid passwords (1 per line).\n"
42 "an optional set of opions may be provided by concatenating any\n"
43 "of the following letters:\n"
44 "     a - Set account code to the password that is entered\n"
45 "     d - Interpret path as database key, not literal file\n"
46 "     r - Remove database key upon successful entry (valid with 'd' only)\n"
47 "\n"
48 "When using a database key, the value associated with the key can be\n"
49 "anything.\n"
50 "Returns 0 if the user enters a valid password within three\n"
51 "tries, or -1 otherwise (or on hangup).\n";
52
53 STANDARD_LOCAL_USER;
54
55 LOCAL_USER_DECL;
56
57 static int auth_exec(struct ast_channel *chan, void *data)
58 {
59         int res=0;
60         int retries;
61         struct localuser *u;
62         char password[256]="";
63         char passwd[256];
64         char *opts;
65         char *prompt;
66         if (!data || !strlen(data)) {
67                 ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
68                 return -1;
69         }
70         LOCAL_USER_ADD(u);
71         if (chan->_state != AST_STATE_UP) {
72                 res = ast_answer(chan);
73                 if (res) {
74                         LOCAL_USER_REMOVE(u);
75                         return -1;
76                 }
77         }
78         strncpy(password, data, sizeof(password) - 1);
79         opts=strchr(password, '|');
80         if (opts) {
81                 *opts = 0;
82                 opts++;
83         } else
84                 opts = "";
85         /* Start asking for password */
86         prompt = "agent-pass";
87         for (retries = 0; retries < 3; retries++) {
88                 res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
89                 if (res < 0)
90                         break;
91                 res = 0;
92                 if (password[0] == '/') {
93                         if (strchr(opts, 'd')) {
94                                 char tmp[256];
95                                 /* Compare against a database key */
96                                 if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
97                                         /* It's a good password */
98                                         if (strchr(opts, 'r')) {
99                                                 ast_db_del(password + 1, passwd);
100                                         }
101                                         break;
102                                 }
103                         } else {
104                                 /* Compare against a file */
105                                 FILE *f;
106                                 f = fopen(password, "r");
107                                 if (f) {
108                                         char buf[256] = "";
109                                         while(!feof(f)) {
110                                                 fgets(buf, sizeof(buf), f);
111                                                 if (!feof(f) && strlen(buf)) {
112                                                         buf[strlen(buf) - 1] = '\0';
113                                                         if (strlen(buf) && !strcmp(passwd, buf))
114                                                                 break;
115                                                 }
116                                         }
117                                         fclose(f);
118                                         if (strlen(buf) && !strcmp(passwd, buf))
119                                                 break;
120                                 } else 
121                                         ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
122                         }
123                 } else {
124                         /* Compare against a fixed password */
125                         if (!strcmp(passwd, password)) 
126                                 break;
127                 }
128                 prompt="auth-incorrect";
129         }
130         if ((retries < 3) && !res) {
131                 if (strchr(opts, 'a')) 
132                         ast_cdr_setaccount(chan, passwd);
133                 res = ast_streamfile(chan, "auth-thankyou", chan->language);
134                 if (!res)
135                         res = ast_waitstream(chan, "");
136         } else {
137                 if (!res)
138                         res = ast_streamfile(chan, "vm-goodbye", chan->language);
139                 if (!res)
140                         res = ast_waitstream(chan, "");
141                 res = -1;
142         }
143         LOCAL_USER_REMOVE(u);
144         return res;
145 }
146
147 int unload_module(void)
148 {
149         STANDARD_HANGUP_LOCALUSERS;
150         return ast_unregister_application(app);
151 }
152
153 int load_module(void)
154 {
155         return ast_register_application(app, auth_exec, synopsis, descrip);
156 }
157
158 char *description(void)
159 {
160         return tdesc;
161 }
162
163 int usecount(void)
164 {
165         int res;
166         STANDARD_USECOUNT(res);
167         return res;
168 }
169
170 char *key()
171 {
172         return ASTERISK_GPL_KEY;
173 }