00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <math.h>
00033 #include <sys/time.h>
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00038
00039 #include "asterisk/lock.h"
00040 #include "asterisk/file.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/indications.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/translate.h"
00048 #include "asterisk/ulaw.h"
00049 #include "asterisk/callerid.h"
00050
00051 static char *tdesc = "DISA (Direct Inward System Access) Application";
00052
00053 static char *app = "DISA";
00054
00055 static char *synopsis = "DISA (Direct Inward System Access)";
00056
00057 static char *descrip =
00058 "DISA(<numeric passcode>[|<context>]) or disa(<filename>)\n"
00059 "The DISA, Direct Inward System Access, application allows someone from \n"
00060 "outside the telephone switch (PBX) to obtain an \"internal\" system \n"
00061 "dialtone and to place calls from it as if they were placing a call from \n"
00062 "within the switch.\n"
00063 "DISA plays a dialtone. The user enters their numeric passcode, followed by\n"
00064 "the pound sign (#). If the passcode is correct, the user is then given\n"
00065 "system dialtone on which a call may be placed. Obviously, this type\n"
00066 "of access has SERIOUS security implications, and GREAT care must be\n"
00067 "taken NOT to compromise your security.\n\n"
00068 "There is a possibility of accessing DISA without password. Simply\n"
00069 "exchange your password with \"no-password\".\n\n"
00070 " Example: exten => s,1,DISA(no-password|local)\n\n"
00071 "Be aware that using this compromises the security of your PBX.\n\n"
00072 "The arguments to this application (in extensions.conf) allow either\n"
00073 "specification of a single global passcode (that everyone uses), or\n"
00074 "individual passcodes contained in a file. It also allow specification\n"
00075 "of the context on which the user will be dialing. If no context is\n"
00076 "specified, the DISA application defaults the context to \"disa\".\n"
00077 "Presumably a normal system will have a special context set up\n"
00078 "for DISA use with some or a lot of restrictions. \n\n"
00079 "The file that contains the passcodes (if used) allows specification\n"
00080 "of either just a passcode (defaulting to the \"disa\" context, or\n"
00081 "passcode|context on each line of the file. The file may contain blank\n"
00082 "lines, or comments starting with \"#\" or \";\". In addition, the\n"
00083 "above arguments may have |new-callerid-string appended to them, to\n"
00084 "specify a new (different) callerid to be used for this call, for\n"
00085 "example: numeric-passcode|context|\"My Phone\" <(234) 123-4567> or \n"
00086 "full-pathname-of-passcode-file|\"My Phone\" <(234) 123-4567>. Last\n"
00087 "but not least, |mailbox[@context] may be appended, which will cause\n"
00088 "a stutter-dialtone (indication \"dialrecall\") to be used, if the\n"
00089 "specified mailbox contains any new messages, for example:\n"
00090 "numeric-passcode|context||1234 (w/a changing callerid). Note that\n"
00091 "in the case of specifying the numeric-passcode, the context must be\n"
00092 "specified if the callerid is specified also.\n\n"
00093 "If login is successful, the application looks up the dialed number in\n"
00094 "the specified (or default) context, and executes it if found.\n"
00095 "If the user enters an invalid extension and extension \"i\" (invalid) \n"
00096 "exists in the context, it will be used.\n";
00097
00098 STANDARD_LOCAL_USER;
00099
00100 LOCAL_USER_DECL;
00101
00102 static void play_dialtone(struct ast_channel *chan, char *mailbox)
00103 {
00104 const struct tone_zone_sound *ts = NULL;
00105 if(ast_app_has_voicemail(mailbox, NULL))
00106 ts = ast_get_indication_tone(chan->zone, "dialrecall");
00107 else
00108 ts = ast_get_indication_tone(chan->zone, "dial");
00109 if (ts)
00110 ast_playtones_start(chan, 0, ts->data, 0);
00111 else
00112 ast_tonepair_start(chan, 350, 440, 0, 0);
00113 }
00114
00115 static int disa_exec(struct ast_channel *chan, void *data)
00116 {
00117 int i,j,k,x,did_ignore;
00118 int firstdigittimeout = 20000;
00119 int digittimeout = 10000;
00120 struct localuser *u;
00121 char *tmp, exten[AST_MAX_EXTENSION],acctcode[20]="";
00122 char pwline[256];
00123 char ourcidname[256],ourcidnum[256];
00124 struct ast_frame *f;
00125 struct timeval lastdigittime;
00126 int res;
00127 time_t rstart;
00128 FILE *fp;
00129 AST_DECLARE_APP_ARGS(args,
00130 AST_APP_ARG(passcode);
00131 AST_APP_ARG(context);
00132 AST_APP_ARG(cid);
00133 AST_APP_ARG(mailbox);
00134 );
00135
00136 if (ast_strlen_zero(data)) {
00137 ast_log(LOG_WARNING, "disa requires an argument (passcode/passcode file)\n");
00138 return -1;
00139 }
00140
00141 LOCAL_USER_ADD(u);
00142
00143 if (chan->pbx) {
00144 firstdigittimeout = chan->pbx->rtimeout*1000;
00145 digittimeout = chan->pbx->dtimeout*1000;
00146 }
00147
00148 if (ast_set_write_format(chan,AST_FORMAT_ULAW)) {
00149 ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n",chan->name);
00150 LOCAL_USER_REMOVE(u);
00151 return -1;
00152 }
00153 if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
00154 ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n",chan->name);
00155 LOCAL_USER_REMOVE(u);
00156 return -1;
00157 }
00158
00159 ast_log(LOG_DEBUG, "Digittimeout: %d\n", digittimeout);
00160 ast_log(LOG_DEBUG, "Responsetimeout: %d\n", firstdigittimeout);
00161
00162 tmp = ast_strdupa(data);
00163 if (!tmp) {
00164 ast_log(LOG_ERROR, "Out of memory\n");
00165 LOCAL_USER_REMOVE(u);
00166 return -1;
00167 }
00168
00169 AST_STANDARD_APP_ARGS(args, tmp);
00170
00171 if (ast_strlen_zero(args.context))
00172 args.context = "disa";
00173 if (ast_strlen_zero(args.mailbox))
00174 args.mailbox = "";
00175
00176 ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
00177
00178 if (chan->_state != AST_STATE_UP) {
00179
00180 ast_answer(chan);
00181 }
00182 i = k = x = 0;
00183 did_ignore = 0;
00184 exten[0] = 0;
00185 acctcode[0] = 0;
00186
00187
00188 ast_log(LOG_DEBUG, "Context: %s\n",args.context);
00189
00190 if (!strcasecmp(args.passcode, "no-password")) {
00191 k |= 1;
00192 ast_log(LOG_DEBUG, "DISA no-password login success\n");
00193 }
00194 lastdigittime = ast_tvnow();
00195
00196 play_dialtone(chan, args.mailbox);
00197
00198 for (;;) {
00199
00200 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
00201 ((k&2) ? digittimeout : firstdigittimeout))
00202 {
00203 ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
00204 ((k&1) ? "extension" : "password"),chan->name);
00205 break;
00206 }
00207 if ((res = ast_waitfor(chan, -1) < 0)) {
00208 ast_log(LOG_DEBUG, "Waitfor returned %d\n", res);
00209 continue;
00210 }
00211
00212 f = ast_read(chan);
00213 if (f == NULL)
00214 {
00215 LOCAL_USER_REMOVE(u);
00216 return -1;
00217 }
00218 if ((f->frametype == AST_FRAME_CONTROL) &&
00219 (f->subclass == AST_CONTROL_HANGUP))
00220 {
00221 ast_frfree(f);
00222 LOCAL_USER_REMOVE(u);
00223 return -1;
00224 }
00225 if (f->frametype == AST_FRAME_VOICE) {
00226 ast_frfree(f);
00227 continue;
00228 }
00229
00230 if (f->frametype != AST_FRAME_DTMF)
00231 {
00232 ast_frfree(f);
00233 continue;
00234 }
00235
00236 j = f->subclass;
00237 ast_frfree(f);
00238 if (i == 0)
00239 {
00240 k|=2;
00241 ast_playtones_stop(chan);
00242 }
00243 lastdigittime = ast_tvnow();
00244
00245 if (i < AST_MAX_EXTENSION)
00246 {
00247 if (!(k&1))
00248 {
00249 if (j == '#')
00250 {
00251
00252 if (sscanf(args.passcode,"%d",&j) < 1)
00253 {
00254 fp = fopen(args.passcode,"r");
00255 if (!fp)
00256 {
00257 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
00258 LOCAL_USER_REMOVE(u);
00259 return -1;
00260 }
00261 pwline[0] = 0;
00262 while(fgets(pwline,sizeof(pwline) - 1,fp))
00263 {
00264 if (!pwline[0]) continue;
00265 if (pwline[strlen(pwline) - 1] == '\n')
00266 pwline[strlen(pwline) - 1] = 0;
00267 if (!pwline[0]) continue;
00268
00269 if (pwline[0] == '#') continue;
00270 if (pwline[0] == ';') continue;
00271
00272 AST_STANDARD_APP_ARGS(args, pwline);
00273
00274 ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
00275
00276
00277 if (sscanf(args.passcode,"%d",&j) < 1) continue;
00278
00279 if (!strcmp(exten,args.passcode)) {
00280 if (ast_strlen_zero(args.context))
00281 args.context = "disa";
00282 if (ast_strlen_zero(args.mailbox))
00283 args.mailbox = "";
00284 break;
00285 }
00286 }
00287 fclose(fp);
00288 }
00289
00290 if (strcmp(exten,args.passcode))
00291 {
00292 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
00293 goto reorder;
00294
00295 }
00296
00297 ast_log(LOG_DEBUG,"DISA on chan %s password is good\n",chan->name);
00298 play_dialtone(chan, args.mailbox);
00299
00300 k|=1;
00301 i = 0;
00302 exten[sizeof(acctcode)] = 0;
00303 ast_copy_string(acctcode, exten, sizeof(acctcode));
00304 exten[0] = 0;
00305 ast_log(LOG_DEBUG,"Successful DISA log-in on chan %s\n",chan->name);
00306 continue;
00307 }
00308 }
00309
00310 exten[i++] = j;
00311 exten[i] = 0;
00312 if (!(k&1)) continue;
00313
00314
00315 if (ast_ignore_pattern(args.context, exten)) {
00316 play_dialtone(chan, "");
00317 did_ignore = 1;
00318 } else
00319 if (did_ignore) {
00320 ast_playtones_stop(chan);
00321 did_ignore = 0;
00322 }
00323
00324
00325 if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
00326 break;
00327 }
00328 }
00329 }
00330
00331 if (k == 3) {
00332 int recheck = 0;
00333 struct ast_flags flags = { AST_CDR_FLAG_POSTED };
00334
00335 if (!ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
00336 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
00337 exten[0] = 'i';
00338 exten[1] = '\0';
00339 recheck = 1;
00340 }
00341 if (!recheck || ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
00342 ast_playtones_stop(chan);
00343
00344 if (!ast_strlen_zero(args.cid))
00345 {
00346 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
00347 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
00348 }
00349
00350 if (!ast_strlen_zero(acctcode))
00351 ast_copy_string(chan->accountcode, acctcode, sizeof(chan->accountcode));
00352
00353 ast_cdr_reset(chan->cdr, &flags);
00354 ast_explicit_goto(chan, args.context, exten, 1);
00355 LOCAL_USER_REMOVE(u);
00356 return 0;
00357 }
00358 }
00359
00360
00361
00362 reorder:
00363
00364 ast_indicate(chan,AST_CONTROL_CONGESTION);
00365
00366 time(&rstart);
00367 while(time(NULL) < rstart + 10)
00368 {
00369 if (ast_waitfor(chan, -1) < 0)
00370 break;
00371 f = ast_read(chan);
00372 if (!f)
00373 break;
00374 ast_frfree(f);
00375 }
00376 ast_playtones_stop(chan);
00377 LOCAL_USER_REMOVE(u);
00378 return -1;
00379 }
00380
00381 int unload_module(void)
00382 {
00383 int res;
00384
00385 res = ast_unregister_application(app);
00386
00387 STANDARD_HANGUP_LOCALUSERS;
00388
00389 return res;
00390 }
00391
00392 int load_module(void)
00393 {
00394 return ast_register_application(app, disa_exec, synopsis, descrip);
00395 }
00396
00397 char *description(void)
00398 {
00399 return tdesc;
00400 }
00401
00402 int usecount(void)
00403 {
00404 int res;
00405 STANDARD_USECOUNT(res);
00406 return res;
00407 }
00408
00409 char *key(void)
00410 {
00411 return ASTERISK_GPL_KEY;
00412 }