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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include "asterisk.h"
00045
00046 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 314723 $")
00047
00048 #include "asterisk/_private.h"
00049 #include "asterisk/paths.h"
00050 #include <ctype.h>
00051 #include <sys/time.h>
00052 #include <signal.h>
00053 #include <sys/mman.h>
00054 #include <sys/types.h>
00055 #include <regex.h>
00056
00057 #include "asterisk/channel.h"
00058 #include "asterisk/file.h"
00059 #include "asterisk/manager.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/config.h"
00062 #include "asterisk/callerid.h"
00063 #include "asterisk/lock.h"
00064 #include "asterisk/cli.h"
00065 #include "asterisk/app.h"
00066 #include "asterisk/pbx.h"
00067 #include "asterisk/md5.h"
00068 #include "asterisk/acl.h"
00069 #include "asterisk/utils.h"
00070 #include "asterisk/tcptls.h"
00071 #include "asterisk/http.h"
00072 #include "asterisk/ast_version.h"
00073 #include "asterisk/threadstorage.h"
00074 #include "asterisk/linkedlists.h"
00075 #include "asterisk/term.h"
00076 #include "asterisk/astobj2.h"
00077 #include "asterisk/features.h"
00078 #include "asterisk/security_events.h"
00079 #include "asterisk/aoc.h"
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 enum error_type {
00812 UNKNOWN_ACTION = 1,
00813 UNKNOWN_CATEGORY,
00814 UNSPECIFIED_CATEGORY,
00815 UNSPECIFIED_ARGUMENT,
00816 FAILURE_ALLOCATION,
00817 FAILURE_NEWCAT,
00818 FAILURE_DELCAT,
00819 FAILURE_EMPTYCAT,
00820 FAILURE_UPDATE,
00821 FAILURE_DELETE,
00822 FAILURE_APPEND
00823 };
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845 struct eventqent {
00846 int usecount;
00847 int category;
00848 unsigned int seq;
00849 struct timeval tv;
00850 AST_RWLIST_ENTRY(eventqent) eq_next;
00851 char eventdata[1];
00852 };
00853
00854 static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
00855
00856 static const int DEFAULT_ENABLED = 0;
00857 static const int DEFAULT_WEBENABLED = 0;
00858 static const int DEFAULT_BLOCKSOCKETS = 0;
00859 static const int DEFAULT_DISPLAYCONNECTS = 1;
00860 static const int DEFAULT_TIMESTAMPEVENTS = 0;
00861 static const int DEFAULT_HTTPTIMEOUT = 60;
00862 static const int DEFAULT_BROKENEVENTSACTION = 0;
00863 static const int DEFAULT_AUTHTIMEOUT = 30;
00864 static const int DEFAULT_AUTHLIMIT = 50;
00865
00866 static int displayconnects;
00867 static int allowmultiplelogin = 1;
00868 static int timestampevents;
00869 static int httptimeout;
00870 static int broken_events_action;
00871 static int manager_enabled = 0;
00872 static int webmanager_enabled = 0;
00873 static int authtimeout;
00874 static int authlimit;
00875 static char *manager_channelvars;
00876
00877 #define DEFAULT_REALM "asterisk"
00878 static char global_realm[MAXHOSTNAMELEN];
00879
00880 static int block_sockets;
00881 static int unauth_sessions = 0;
00882
00883 static int manager_debug;
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895 #define MAX_BLACKLIST_CMD_LEN 2
00896 static const struct {
00897 const char *words[AST_MAX_CMD_LEN];
00898 } command_blacklist[] = {
00899 {{ "module", "load", NULL }},
00900 {{ "module", "unload", NULL }},
00901 {{ "restart", "gracefully", NULL }},
00902 };
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 struct mansession_session {
00937
00938 struct sockaddr_in sin;
00939 FILE *f;
00940 int fd;
00941 int inuse;
00942 int needdestroy;
00943 pthread_t waiting_thread;
00944 uint32_t managerid;
00945 time_t sessionstart;
00946 struct timeval sessionstart_tv;
00947 time_t sessiontimeout;
00948 char username[80];
00949 char challenge[10];
00950 int authenticated;
00951 int readperm;
00952 int writeperm;
00953 char inbuf[1025];
00954
00955 int inlen;
00956 int send_events;
00957 struct eventqent *last_ev;
00958 int writetimeout;
00959 time_t authstart;
00960 int pending_event;
00961 time_t noncetime;
00962 struct ao2_container *whitefilters;
00963 struct ao2_container *blackfilters;
00964 unsigned long oldnonce;
00965 unsigned long nc;
00966 AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores;
00967 AST_LIST_ENTRY(mansession_session) list;
00968 };
00969
00970
00971
00972
00973
00974
00975 struct mansession {
00976 struct mansession_session *session;
00977 struct ast_tcptls_session_instance *tcptls_session;
00978 FILE *f;
00979 int fd;
00980 int write_error:1;
00981 struct manager_custom_hook *hook;
00982 ast_mutex_t lock;
00983 };
00984
00985 static struct ao2_container *sessions = NULL;
00986
00987 struct manager_channel_variable {
00988 AST_LIST_ENTRY(manager_channel_variable) entry;
00989 unsigned int isfunc:1;
00990 char name[0];
00991 };
00992
00993 static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
00994
00995
00996
00997
00998
00999
01000
01001 struct ast_manager_user {
01002 char username[80];
01003 char *secret;
01004 struct ast_ha *ha;
01005 int readperm;
01006 int writeperm;
01007 int writetimeout;
01008 int displayconnects;
01009 int keep;
01010 struct ao2_container *whitefilters;
01011 struct ao2_container *blackfilters;
01012 char *a1_hash;
01013 AST_RWLIST_ENTRY(ast_manager_user) list;
01014 };
01015
01016
01017 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
01018
01019
01020 static AST_RWLIST_HEAD_STATIC(actions, manager_action);
01021
01022
01023 static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
01024
01025 static void free_channelvars(void);
01026
01027
01028 void ast_manager_register_hook(struct manager_custom_hook *hook)
01029 {
01030 AST_RWLIST_WRLOCK(&manager_hooks);
01031 AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
01032 AST_RWLIST_UNLOCK(&manager_hooks);
01033 }
01034
01035
01036 void ast_manager_unregister_hook(struct manager_custom_hook *hook)
01037 {
01038 AST_RWLIST_WRLOCK(&manager_hooks);
01039 AST_RWLIST_REMOVE(&manager_hooks, hook, list);
01040 AST_RWLIST_UNLOCK(&manager_hooks);
01041 }
01042
01043 int check_manager_enabled()
01044 {
01045 return manager_enabled;
01046 }
01047
01048 int check_webmanager_enabled()
01049 {
01050 return (webmanager_enabled && manager_enabled);
01051 }
01052
01053
01054
01055
01056
01057 static struct eventqent *grab_last(void)
01058 {
01059 struct eventqent *ret;
01060
01061 AST_RWLIST_WRLOCK(&all_events);
01062 ret = AST_RWLIST_LAST(&all_events);
01063
01064
01065
01066 if (ret) {
01067 ast_atomic_fetchadd_int(&ret->usecount, 1);
01068 }
01069 AST_RWLIST_UNLOCK(&all_events);
01070 return ret;
01071 }
01072
01073
01074
01075
01076
01077 static void purge_events(void)
01078 {
01079 struct eventqent *ev;
01080 struct timeval now = ast_tvnow();
01081
01082 AST_RWLIST_WRLOCK(&all_events);
01083 while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
01084 ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
01085 AST_RWLIST_REMOVE_HEAD(&all_events, eq_next);
01086 ast_free(ev);
01087 }
01088
01089 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next) {
01090
01091 if (!AST_RWLIST_NEXT(ev, eq_next)) {
01092 break;
01093 }
01094
01095
01096 if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
01097 AST_RWLIST_REMOVE_CURRENT(eq_next);
01098 ast_free(ev);
01099 }
01100 }
01101 AST_RWLIST_TRAVERSE_SAFE_END;
01102 AST_RWLIST_UNLOCK(&all_events);
01103 }
01104
01105
01106
01107
01108
01109 static const struct permalias {
01110 int num;
01111 const char *label;
01112 } perms[] = {
01113 { EVENT_FLAG_SYSTEM, "system" },
01114 { EVENT_FLAG_CALL, "call" },
01115 { EVENT_FLAG_LOG, "log" },
01116 { EVENT_FLAG_VERBOSE, "verbose" },
01117 { EVENT_FLAG_COMMAND, "command" },
01118 { EVENT_FLAG_AGENT, "agent" },
01119 { EVENT_FLAG_USER, "user" },
01120 { EVENT_FLAG_CONFIG, "config" },
01121 { EVENT_FLAG_DTMF, "dtmf" },
01122 { EVENT_FLAG_REPORTING, "reporting" },
01123 { EVENT_FLAG_CDR, "cdr" },
01124 { EVENT_FLAG_DIALPLAN, "dialplan" },
01125 { EVENT_FLAG_ORIGINATE, "originate" },
01126 { EVENT_FLAG_AGI, "agi" },
01127 { EVENT_FLAG_CC, "cc" },
01128 { EVENT_FLAG_AOC, "aoc" },
01129 { INT_MAX, "all" },
01130 { 0, "none" },
01131 };
01132
01133
01134 static const char *authority_to_str(int authority, struct ast_str **res)
01135 {
01136 int i;
01137 char *sep = "";
01138
01139 ast_str_reset(*res);
01140 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
01141 if (authority & perms[i].num) {
01142 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
01143 sep = ",";
01144 }
01145 }
01146
01147 if (ast_str_strlen(*res) == 0)
01148 ast_str_append(res, 0, "<none>");
01149
01150 return ast_str_buffer(*res);
01151 }
01152
01153
01154
01155
01156
01157
01158 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
01159 {
01160 const char *val = bigstr, *next;
01161
01162 do {
01163 if ((next = strchr(val, delim))) {
01164 if (!strncmp(val, smallstr, (next - val))) {
01165 return 1;
01166 } else {
01167 continue;
01168 }
01169 } else {
01170 return !strcmp(smallstr, val);
01171 }
01172 } while (*(val = (next + 1)));
01173
01174 return 0;
01175 }
01176
01177 static int get_perm(const char *instr)
01178 {
01179 int x = 0, ret = 0;
01180
01181 if (!instr) {
01182 return 0;
01183 }
01184
01185 for (x = 0; x < ARRAY_LEN(perms); x++) {
01186 if (ast_instring(instr, perms[x].label, ',')) {
01187 ret |= perms[x].num;
01188 }
01189 }
01190
01191 return ret;
01192 }
01193
01194
01195
01196
01197
01198 static int strings_to_mask(const char *string)
01199 {
01200 const char *p;
01201
01202 if (ast_strlen_zero(string)) {
01203 return -1;
01204 }
01205
01206 for (p = string; *p; p++) {
01207 if (*p < '0' || *p > '9') {
01208 break;
01209 }
01210 }
01211 if (!*p) {
01212 return atoi(string);
01213 }
01214 if (ast_false(string)) {
01215 return 0;
01216 }
01217 if (ast_true(string)) {
01218 int x, ret = 0;
01219 for (x = 0; x < ARRAY_LEN(perms); x++) {
01220 ret |= perms[x].num;
01221 }
01222 return ret;
01223 }
01224 return get_perm(string);
01225 }
01226
01227
01228
01229 static struct mansession_session *unref_mansession(struct mansession_session *s)
01230 {
01231 int refcount = ao2_ref(s, -1);
01232 if (manager_debug) {
01233 ast_log(LOG_DEBUG, "Mansession: %p refcount now %d\n", s, refcount - 1);
01234 }
01235 return s;
01236 }
01237
01238 static void event_filter_destructor(void *obj)
01239 {
01240 regex_t *regex_filter = obj;
01241 regfree(regex_filter);
01242 }
01243
01244 static void session_destructor(void *obj)
01245 {
01246 struct mansession_session *session = obj;
01247 struct eventqent *eqe = session->last_ev;
01248 struct ast_datastore *datastore;
01249
01250
01251 while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
01252
01253 ast_datastore_free(datastore);
01254 }
01255
01256 if (session->f != NULL) {
01257 fclose(session->f);
01258 }
01259 if (eqe) {
01260 ast_atomic_fetchadd_int(&eqe->usecount, -1);
01261 }
01262
01263 if (session->whitefilters) {
01264 ao2_t_callback(session->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
01265 ao2_t_ref(session->whitefilters, -1 , "decrement ref for white container, should be last one");
01266 }
01267
01268 if (session->blackfilters) {
01269 ao2_t_callback(session->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
01270 ao2_t_ref(session->blackfilters, -1 , "decrement ref for black container, should be last one");
01271 }
01272 }
01273
01274
01275 static struct mansession_session *build_mansession(struct sockaddr_in sin)
01276 {
01277 struct mansession_session *newsession;
01278
01279 if (!(newsession = ao2_alloc(sizeof(*newsession), session_destructor))) {
01280 return NULL;
01281 }
01282
01283 if (!(newsession->whitefilters = ao2_container_alloc(1, NULL, NULL))) {
01284 ao2_ref(newsession, -1);
01285 return NULL;
01286 }
01287
01288 if (!(newsession->blackfilters = ao2_container_alloc(1, NULL, NULL))) {
01289 ao2_ref(newsession, -1);
01290 return NULL;
01291 }
01292
01293 newsession->fd = -1;
01294 newsession->waiting_thread = AST_PTHREADT_NULL;
01295 newsession->writetimeout = 100;
01296 newsession->send_events = -1;
01297 newsession->sin = sin;
01298
01299 ao2_link(sessions, newsession);
01300
01301 return newsession;
01302 }
01303
01304 static int mansession_cmp_fn(void *obj, void *arg, int flags)
01305 {
01306 struct mansession_session *s = obj;
01307 char *str = arg;
01308 return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
01309 }
01310
01311 static void session_destroy(struct mansession_session *s)
01312 {
01313 unref_mansession(s);
01314 ao2_unlink(sessions, s);
01315 }
01316
01317
01318 static int check_manager_session_inuse(const char *name)
01319 {
01320 struct mansession_session *session = ao2_find(sessions, (char *) name, 0);
01321 int inuse = 0;
01322
01323 if (session) {
01324 inuse = 1;
01325 unref_mansession(session);
01326 }
01327 return inuse;
01328 }
01329
01330
01331
01332
01333
01334
01335 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
01336 {
01337 struct ast_manager_user *user = NULL;
01338
01339 AST_RWLIST_TRAVERSE(&users, user, list) {
01340 if (!strcasecmp(user->username, name)) {
01341 break;
01342 }
01343 }
01344
01345 return user;
01346 }
01347
01348
01349
01350
01351
01352 static int manager_displayconnects (struct mansession_session *session)
01353 {
01354 struct ast_manager_user *user = NULL;
01355 int ret = 0;
01356
01357 AST_RWLIST_RDLOCK(&users);
01358 if ((user = get_manager_by_name_locked (session->username))) {
01359 ret = user->displayconnects;
01360 }
01361 AST_RWLIST_UNLOCK(&users);
01362
01363 return ret;
01364 }
01365
01366 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01367 {
01368 struct manager_action *cur;
01369 struct ast_str *authority;
01370 int num, l, which;
01371 char *ret = NULL;
01372 #ifdef AST_XML_DOCS
01373 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
01374 #endif
01375
01376 switch (cmd) {
01377 case CLI_INIT:
01378 e->command = "manager show command";
01379 e->usage =
01380 "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
01381 " Shows the detailed description for a specific Asterisk manager interface command.\n";
01382 return NULL;
01383 case CLI_GENERATE:
01384 l = strlen(a->word);
01385 which = 0;
01386 AST_RWLIST_RDLOCK(&actions);
01387 AST_RWLIST_TRAVERSE(&actions, cur, list) {
01388 if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
01389 ret = ast_strdup(cur->action);
01390 break;
01391 }
01392 }
01393 AST_RWLIST_UNLOCK(&actions);
01394 return ret;
01395 }
01396 authority = ast_str_alloca(80);
01397 if (a->argc < 4) {
01398 return CLI_SHOWUSAGE;
01399 }
01400
01401 #ifdef AST_XML_DOCS
01402
01403 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01404 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
01405 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01406 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
01407 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
01408 #endif
01409
01410 AST_RWLIST_RDLOCK(&actions);
01411 AST_RWLIST_TRAVERSE(&actions, cur, list) {
01412 for (num = 3; num < a->argc; num++) {
01413 if (!strcasecmp(cur->action, a->argv[num])) {
01414 #ifdef AST_XML_DOCS
01415 if (cur->docsrc == AST_XML_DOC) {
01416 ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
01417 syntax_title,
01418 ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1),
01419 synopsis_title,
01420 ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1),
01421 description_title,
01422 ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1),
01423 arguments_title,
01424 ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1),
01425 seealso_title,
01426 ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1));
01427 } else {
01428 #endif
01429 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
01430 cur->action, cur->synopsis,
01431 authority_to_str(cur->authority, &authority),
01432 S_OR(cur->description, ""));
01433 #ifdef AST_XML_DOCS
01434 }
01435 #endif
01436 }
01437 }
01438 }
01439 AST_RWLIST_UNLOCK(&actions);
01440
01441 return CLI_SUCCESS;
01442 }
01443
01444 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01445 {
01446 switch (cmd) {
01447 case CLI_INIT:
01448 e->command = "manager set debug [on|off]";
01449 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
01450 return NULL;
01451 case CLI_GENERATE:
01452 return NULL;
01453 }
01454
01455 if (a->argc == 3) {
01456 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
01457 } else if (a->argc == 4) {
01458 if (!strcasecmp(a->argv[3], "on")) {
01459 manager_debug = 1;
01460 } else if (!strcasecmp(a->argv[3], "off")) {
01461 manager_debug = 0;
01462 } else {
01463 return CLI_SHOWUSAGE;
01464 }
01465 }
01466 return CLI_SUCCESS;
01467 }
01468
01469 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01470 {
01471 struct ast_manager_user *user = NULL;
01472 int l, which;
01473 char *ret = NULL;
01474 struct ast_str *rauthority = ast_str_alloca(128);
01475 struct ast_str *wauthority = ast_str_alloca(128);
01476
01477 switch (cmd) {
01478 case CLI_INIT:
01479 e->command = "manager show user";
01480 e->usage =
01481 " Usage: manager show user <user>\n"
01482 " Display all information related to the manager user specified.\n";
01483 return NULL;
01484 case CLI_GENERATE:
01485 l = strlen(a->word);
01486 which = 0;
01487 if (a->pos != 3) {
01488 return NULL;
01489 }
01490 AST_RWLIST_RDLOCK(&users);
01491 AST_RWLIST_TRAVERSE(&users, user, list) {
01492 if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
01493 ret = ast_strdup(user->username);
01494 break;
01495 }
01496 }
01497 AST_RWLIST_UNLOCK(&users);
01498 return ret;
01499 }
01500
01501 if (a->argc != 4) {
01502 return CLI_SHOWUSAGE;
01503 }
01504
01505 AST_RWLIST_RDLOCK(&users);
01506
01507 if (!(user = get_manager_by_name_locked(a->argv[3]))) {
01508 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
01509 AST_RWLIST_UNLOCK(&users);
01510 return CLI_SUCCESS;
01511 }
01512
01513 ast_cli(a->fd, "\n");
01514 ast_cli(a->fd,
01515 " username: %s\n"
01516 " secret: %s\n"
01517 " acl: %s\n"
01518 " read perm: %s\n"
01519 " write perm: %s\n"
01520 "displayconnects: %s\n",
01521 (user->username ? user->username : "(N/A)"),
01522 (user->secret ? "<Set>" : "(N/A)"),
01523 (user->ha ? "yes" : "no"),
01524 authority_to_str(user->readperm, &rauthority),
01525 authority_to_str(user->writeperm, &wauthority),
01526 (user->displayconnects ? "yes" : "no"));
01527
01528 AST_RWLIST_UNLOCK(&users);
01529
01530 return CLI_SUCCESS;
01531 }
01532
01533 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01534 {
01535 struct ast_manager_user *user = NULL;
01536 int count_amu = 0;
01537 switch (cmd) {
01538 case CLI_INIT:
01539 e->command = "manager show users";
01540 e->usage =
01541 "Usage: manager show users\n"
01542 " Prints a listing of all managers that are currently configured on that\n"
01543 " system.\n";
01544 return NULL;
01545 case CLI_GENERATE:
01546 return NULL;
01547 }
01548 if (a->argc != 3) {
01549 return CLI_SHOWUSAGE;
01550 }
01551
01552 AST_RWLIST_RDLOCK(&users);
01553
01554
01555 if (AST_RWLIST_EMPTY(&users)) {
01556 ast_cli(a->fd, "There are no manager users.\n");
01557 AST_RWLIST_UNLOCK(&users);
01558 return CLI_SUCCESS;
01559 }
01560
01561 ast_cli(a->fd, "\nusername\n--------\n");
01562
01563 AST_RWLIST_TRAVERSE(&users, user, list) {
01564 ast_cli(a->fd, "%s\n", user->username);
01565 count_amu++;
01566 }
01567
01568 AST_RWLIST_UNLOCK(&users);
01569
01570 ast_cli(a->fd,"-------------------\n"
01571 "%d manager users configured.\n", count_amu);
01572 return CLI_SUCCESS;
01573 }
01574
01575
01576 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01577 {
01578 struct manager_action *cur;
01579 struct ast_str *authority;
01580 #define HSMC_FORMAT " %-15.15s %-15.15s %-55.55s\n"
01581 switch (cmd) {
01582 case CLI_INIT:
01583 e->command = "manager show commands";
01584 e->usage =
01585 "Usage: manager show commands\n"
01586 " Prints a listing of all the available Asterisk manager interface commands.\n";
01587 return NULL;
01588 case CLI_GENERATE:
01589 return NULL;
01590 }
01591 authority = ast_str_alloca(80);
01592 ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
01593 ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
01594
01595 AST_RWLIST_RDLOCK(&actions);
01596 AST_RWLIST_TRAVERSE(&actions, cur, list)
01597 ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
01598 AST_RWLIST_UNLOCK(&actions);
01599
01600 return CLI_SUCCESS;
01601 }
01602
01603
01604 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01605 {
01606 struct mansession_session *session;
01607 time_t now = time(NULL);
01608 #define HSMCONN_FORMAT1 " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
01609 #define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
01610 int count = 0;
01611 struct ao2_iterator i;
01612
01613 switch (cmd) {
01614 case CLI_INIT:
01615 e->command = "manager show connected";
01616 e->usage =
01617 "Usage: manager show connected\n"
01618 " Prints a listing of the users that are currently connected to the\n"
01619 "Asterisk manager interface.\n";
01620 return NULL;
01621 case CLI_GENERATE:
01622 return NULL;
01623 }
01624
01625 ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
01626
01627 i = ao2_iterator_init(sessions, 0);
01628 while ((session = ao2_iterator_next(&i))) {
01629 ao2_lock(session);
01630 ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
01631 count++;
01632 ao2_unlock(session);
01633 unref_mansession(session);
01634 }
01635 ao2_iterator_destroy(&i);
01636 ast_cli(a->fd, "%d users connected.\n", count);
01637
01638 return CLI_SUCCESS;
01639 }
01640
01641
01642
01643 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01644 {
01645 struct eventqent *s;
01646 switch (cmd) {
01647 case CLI_INIT:
01648 e->command = "manager show eventq";
01649 e->usage =
01650 "Usage: manager show eventq\n"
01651 " Prints a listing of all events pending in the Asterisk manger\n"
01652 "event queue.\n";
01653 return NULL;
01654 case CLI_GENERATE:
01655 return NULL;
01656 }
01657 AST_RWLIST_RDLOCK(&all_events);
01658 AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
01659 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
01660 ast_cli(a->fd, "Category: %d\n", s->category);
01661 ast_cli(a->fd, "Event:\n%s", s->eventdata);
01662 }
01663 AST_RWLIST_UNLOCK(&all_events);
01664
01665 return CLI_SUCCESS;
01666 }
01667
01668
01669 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01670 {
01671 switch (cmd) {
01672 case CLI_INIT:
01673 e->command = "manager reload";
01674 e->usage =
01675 "Usage: manager reload\n"
01676 " Reloads the manager configuration.\n";
01677 return NULL;
01678 case CLI_GENERATE:
01679 return NULL;
01680 }
01681 if (a->argc > 2) {
01682 return CLI_SHOWUSAGE;
01683 }
01684 reload_manager();
01685 return CLI_SUCCESS;
01686 }
01687
01688 static struct eventqent *advance_event(struct eventqent *e)
01689 {
01690 struct eventqent *next;
01691
01692 AST_RWLIST_RDLOCK(&all_events);
01693 if ((next = AST_RWLIST_NEXT(e, eq_next))) {
01694 ast_atomic_fetchadd_int(&next->usecount, 1);
01695 ast_atomic_fetchadd_int(&e->usecount, -1);
01696 }
01697 AST_RWLIST_UNLOCK(&all_events);
01698 return next;
01699 }
01700
01701
01702
01703
01704
01705
01706
01707 #define GET_HEADER_FIRST_MATCH 0
01708 #define GET_HEADER_LAST_MATCH 1
01709 #define GET_HEADER_SKIP_EMPTY 2
01710 static const char *__astman_get_header(const struct message *m, char *var, int mode)
01711 {
01712 int x, l = strlen(var);
01713 const char *result = "";
01714
01715 for (x = 0; x < m->hdrcount; x++) {
01716 const char *h = m->headers[x];
01717 if (!strncasecmp(var, h, l) && h[l] == ':') {
01718 const char *value = h + l + 1;
01719 value = ast_skip_blanks(value);
01720
01721 if (mode & GET_HEADER_SKIP_EMPTY && ast_strlen_zero(value))
01722 continue;
01723 if (mode & GET_HEADER_LAST_MATCH)
01724 result = value;
01725 else
01726 return value;
01727 }
01728 }
01729
01730 return "";
01731 }
01732
01733
01734
01735
01736
01737
01738 const char *astman_get_header(const struct message *m, char *var)
01739 {
01740 return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH);
01741 }
01742
01743
01744 struct ast_variable *astman_get_variables(const struct message *m)
01745 {
01746 int varlen, x, y;
01747 struct ast_variable *head = NULL, *cur;
01748
01749 AST_DECLARE_APP_ARGS(args,
01750 AST_APP_ARG(vars)[32];
01751 );
01752
01753 varlen = strlen("Variable: ");
01754
01755 for (x = 0; x < m->hdrcount; x++) {
01756 char *parse, *var, *val;
01757
01758 if (strncasecmp("Variable: ", m->headers[x], varlen)) {
01759 continue;
01760 }
01761 parse = ast_strdupa(m->headers[x] + varlen);
01762
01763 AST_STANDARD_APP_ARGS(args, parse);
01764 if (!args.argc) {
01765 continue;
01766 }
01767 for (y = 0; y < args.argc; y++) {
01768 if (!args.vars[y]) {
01769 continue;
01770 }
01771 var = val = ast_strdupa(args.vars[y]);
01772 strsep(&val, "=");
01773 if (!val || ast_strlen_zero(var)) {
01774 continue;
01775 }
01776 cur = ast_variable_new(var, val, "");
01777 cur->next = head;
01778 head = cur;
01779 }
01780 }
01781
01782 return head;
01783 }
01784
01785
01786
01787 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
01788 {
01789 const char *action;
01790 int ret = 0;
01791 struct manager_action *tmp;
01792 struct mansession s = {.session = NULL, };
01793 struct message m = { 0 };
01794 char header_buf[1025] = { '\0' };
01795 const char *src = msg;
01796 int x = 0;
01797 int curlen;
01798
01799 if (hook == NULL) {
01800 return -1;
01801 }
01802
01803
01804 curlen = strlen(msg);
01805 for (x = 0; x < curlen; x++) {
01806 int cr;
01807 if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
01808 cr = 2;
01809 else if (src[x] == '\n')
01810 cr = 1;
01811 else
01812 continue;
01813
01814 if (x) {
01815 memmove(header_buf, src, x);
01816 header_buf[x] = '\0';
01817 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
01818 }
01819 x += cr;
01820 curlen -= x;
01821 src += x;
01822 x = -1;
01823 }
01824
01825 action = astman_get_header(&m,"Action");
01826 if (action && strcasecmp(action,"login")) {
01827
01828 AST_RWLIST_RDLOCK(&actions);
01829 AST_RWLIST_TRAVERSE(&actions, tmp, list) {
01830 if (strcasecmp(action, tmp->action))
01831 continue;
01832
01833
01834
01835
01836
01837 s.hook = hook;
01838 s.f = (void*)1;
01839 ret = tmp->func(&s, &m);
01840 break;
01841 }
01842 AST_RWLIST_UNLOCK(&actions);
01843 }
01844 return ret;
01845 }
01846
01847
01848
01849
01850
01851
01852 static int send_string(struct mansession *s, char *string)
01853 {
01854 int res;
01855 FILE *f = s->f ? s->f : s->session->f;
01856 int fd = s->f ? s->fd : s->session->fd;
01857
01858
01859 if (s->hook) {
01860
01861
01862
01863
01864 s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
01865 return 0;
01866 }
01867
01868 if ((res = ast_careful_fwrite(f, fd, string, strlen(string), s->session->writetimeout))) {
01869 s->write_error = 1;
01870 }
01871
01872 return res;
01873 }
01874
01875
01876
01877
01878
01879
01880
01881
01882 AST_THREADSTORAGE(astman_append_buf);
01883 AST_THREADSTORAGE(userevent_buf);
01884
01885
01886 #define ASTMAN_APPEND_BUF_INITSIZE 256
01887
01888
01889
01890
01891 void astman_append(struct mansession *s, const char *fmt, ...)
01892 {
01893 va_list ap;
01894 struct ast_str *buf;
01895
01896 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
01897 return;
01898 }
01899
01900 va_start(ap, fmt);
01901 ast_str_set_va(&buf, 0, fmt, ap);
01902 va_end(ap);
01903
01904 if (s->f != NULL || s->session->f != NULL) {
01905 send_string(s, ast_str_buffer(buf));
01906 } else {
01907 ast_verbose("fd == -1 in astman_append, should not happen\n");
01908 }
01909 }
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 #define MSG_MOREDATA ((char *)astman_send_response)
01928 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
01929 {
01930 const char *id = astman_get_header(m, "ActionID");
01931
01932 astman_append(s, "Response: %s\r\n", resp);
01933 if (!ast_strlen_zero(id)) {
01934 astman_append(s, "ActionID: %s\r\n", id);
01935 }
01936 if (listflag) {
01937 astman_append(s, "EventList: %s\r\n", listflag);
01938 }
01939 if (msg == MSG_MOREDATA) {
01940 return;
01941 } else if (msg) {
01942 astman_append(s, "Message: %s\r\n\r\n", msg);
01943 } else {
01944 astman_append(s, "\r\n");
01945 }
01946 }
01947
01948 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
01949 {
01950 astman_send_response_full(s, m, resp, msg, NULL);
01951 }
01952
01953 void astman_send_error(struct mansession *s, const struct message *m, char *error)
01954 {
01955 astman_send_response_full(s, m, "Error", error, NULL);
01956 }
01957
01958 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
01959 {
01960 astman_send_response_full(s, m, "Success", msg, NULL);
01961 }
01962
01963 static void astman_start_ack(struct mansession *s, const struct message *m)
01964 {
01965 astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
01966 }
01967
01968 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
01969 {
01970 astman_send_response_full(s, m, "Success", msg, listflag);
01971 }
01972
01973
01974 static void mansession_lock(struct mansession *s)
01975 {
01976 ast_mutex_lock(&s->lock);
01977 }
01978
01979
01980 static void mansession_unlock(struct mansession *s)
01981 {
01982 ast_mutex_unlock(&s->lock);
01983 }
01984
01985
01986
01987
01988
01989 static int set_eventmask(struct mansession *s, const char *eventmask)
01990 {
01991 int maskint = strings_to_mask(eventmask);
01992
01993 ao2_lock(s->session);
01994 if (maskint >= 0) {
01995 s->session->send_events = maskint;
01996 }
01997 ao2_unlock(s->session);
01998
01999 return maskint;
02000 }
02001
02002 static enum ast_security_event_transport_type mansession_get_transport(const struct mansession *s)
02003 {
02004 return s->tcptls_session->parent->tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS :
02005 AST_SECURITY_EVENT_TRANSPORT_TCP;
02006 }
02007
02008 static struct sockaddr_in *mansession_encode_sin_local(const struct mansession *s,
02009 struct sockaddr_in *sin_local)
02010 {
02011 ast_sockaddr_to_sin(&s->tcptls_session->parent->local_address,
02012 sin_local);
02013
02014 return sin_local;
02015 }
02016
02017 static void report_invalid_user(const struct mansession *s, const char *username)
02018 {
02019 struct sockaddr_in sin_local;
02020 char session_id[32];
02021 struct ast_security_event_inval_acct_id inval_acct_id = {
02022 .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
02023 .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
02024 .common.service = "AMI",
02025 .common.account_id = username,
02026 .common.session_tv = &s->session->sessionstart_tv,
02027 .common.local_addr = {
02028 .sin = mansession_encode_sin_local(s, &sin_local),
02029 .transport = mansession_get_transport(s),
02030 },
02031 .common.remote_addr = {
02032 .sin = &s->session->sin,
02033 .transport = mansession_get_transport(s),
02034 },
02035 .common.session_id = session_id,
02036 };
02037
02038 snprintf(session_id, sizeof(session_id), "%p", s);
02039
02040 ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
02041 }
02042
02043 static void report_failed_acl(const struct mansession *s, const char *username)
02044 {
02045 struct sockaddr_in sin_local;
02046 char session_id[32];
02047 struct ast_security_event_failed_acl failed_acl_event = {
02048 .common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
02049 .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
02050 .common.service = "AMI",
02051 .common.account_id = username,
02052 .common.session_tv = &s->session->sessionstart_tv,
02053 .common.local_addr = {
02054 .sin = mansession_encode_sin_local(s, &sin_local),
02055 .transport = mansession_get_transport(s),
02056 },
02057 .common.remote_addr = {
02058 .sin = &s->session->sin,
02059 .transport = mansession_get_transport(s),
02060 },
02061 .common.session_id = session_id,
02062 };
02063
02064 snprintf(session_id, sizeof(session_id), "%p", s->session);
02065
02066 ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
02067 }
02068
02069 static void report_inval_password(const struct mansession *s, const char *username)
02070 {
02071 struct sockaddr_in sin_local;
02072 char session_id[32];
02073 struct ast_security_event_inval_password inval_password = {
02074 .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
02075 .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
02076 .common.service = "AMI",
02077 .common.account_id = username,
02078 .common.session_tv = &s->session->sessionstart_tv,
02079 .common.local_addr = {
02080 .sin = mansession_encode_sin_local(s, &sin_local),
02081 .transport = mansession_get_transport(s),
02082 },
02083 .common.remote_addr = {
02084 .sin = &s->session->sin,
02085 .transport = mansession_get_transport(s),
02086 },
02087 .common.session_id = session_id,
02088 };
02089
02090 snprintf(session_id, sizeof(session_id), "%p", s->session);
02091
02092 ast_security_event_report(AST_SEC_EVT(&inval_password));
02093 }
02094
02095 static void report_auth_success(const struct mansession *s)
02096 {
02097 struct sockaddr_in sin_local;
02098 char session_id[32];
02099 struct ast_security_event_successful_auth successful_auth = {
02100 .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
02101 .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
02102 .common.service = "AMI",
02103 .common.account_id = s->session->username,
02104 .common.session_tv = &s->session->sessionstart_tv,
02105 .common.local_addr = {
02106 .sin = mansession_encode_sin_local(s, &sin_local),
02107 .transport = mansession_get_transport(s),
02108 },
02109 .common.remote_addr = {
02110 .sin = &s->session->sin,
02111 .transport = mansession_get_transport(s),
02112 },
02113 .common.session_id = session_id,
02114 };
02115
02116 snprintf(session_id, sizeof(session_id), "%p", s->session);
02117
02118 ast_security_event_report(AST_SEC_EVT(&successful_auth));
02119 }
02120
02121 static void report_req_not_allowed(const struct mansession *s, const char *action)
02122 {
02123 struct sockaddr_in sin_local;
02124 char session_id[32];
02125 char request_type[64];
02126 struct ast_security_event_req_not_allowed req_not_allowed = {
02127 .common.event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED,
02128 .common.version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
02129 .common.service = "AMI",
02130 .common.account_id = s->session->username,
02131 .common.session_tv = &s->session->sessionstart_tv,
02132 .common.local_addr = {
02133 .sin = mansession_encode_sin_local(s, &sin_local),
02134 .transport = mansession_get_transport(s),
02135 },
02136 .common.remote_addr = {
02137 .sin = &s->session->sin,
02138 .transport = mansession_get_transport(s),
02139 },
02140 .common.session_id = session_id,
02141
02142 .request_type = request_type,
02143 };
02144
02145 snprintf(session_id, sizeof(session_id), "%p", s->session);
02146 snprintf(request_type, sizeof(request_type), "Action: %s", action);
02147
02148 ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
02149 }
02150
02151 static void report_req_bad_format(const struct mansession *s, const char *action)
02152 {
02153 struct sockaddr_in sin_local;
02154 char session_id[32];
02155 char request_type[64];
02156 struct ast_security_event_req_bad_format req_bad_format = {
02157 .common.event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT,
02158 .common.version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
02159 .common.service = "AMI",
02160 .common.account_id = s->session->username,
02161 .common.session_tv = &s->session->sessionstart_tv,
02162 .common.local_addr = {
02163 .sin = mansession_encode_sin_local(s, &sin_local),
02164 .transport = mansession_get_transport(s),
02165 },
02166 .common.remote_addr = {
02167 .sin = &s->session->sin,
02168 .transport = mansession_get_transport(s),
02169 },
02170 .common.session_id = session_id,
02171
02172 .request_type = request_type,
02173 };
02174
02175 snprintf(session_id, sizeof(session_id), "%p", s->session);
02176 snprintf(request_type, sizeof(request_type), "Action: %s", action);
02177
02178 ast_security_event_report(AST_SEC_EVT(&req_bad_format));
02179 }
02180
02181 static void report_failed_challenge_response(const struct mansession *s,
02182 const char *response, const char *expected_response)
02183 {
02184 struct sockaddr_in sin_local;
02185 char session_id[32];
02186 struct ast_security_event_chal_resp_failed chal_resp_failed = {
02187 .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
02188 .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
02189 .common.service = "AMI",
02190 .common.account_id = s->session->username,
02191 .common.session_tv = &s->session->sessionstart_tv,
02192 .common.local_addr = {
02193 .sin = mansession_encode_sin_local(s, &sin_local),
02194 .transport = mansession_get_transport(s),
02195 },
02196 .common.remote_addr = {
02197 .sin = &s->session->sin,
02198 .transport = mansession_get_transport(s),
02199 },
02200 .common.session_id = session_id,
02201
02202 .challenge = s->session->challenge,
02203 .response = response,
02204 .expected_response = expected_response,
02205 };
02206
02207 snprintf(session_id, sizeof(session_id), "%p", s->session);
02208
02209 ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
02210 }
02211
02212 static void report_session_limit(const struct mansession *s)
02213 {
02214 struct sockaddr_in sin_local;
02215 char session_id[32];
02216 struct ast_security_event_session_limit session_limit = {
02217 .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
02218 .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
02219 .common.service = "AMI",
02220 .common.account_id = s->session->username,
02221 .common.session_tv = &s->session->sessionstart_tv,
02222 .common.local_addr = {
02223 .sin = mansession_encode_sin_local(s, &sin_local),
02224 .transport = mansession_get_transport(s),
02225 },
02226 .common.remote_addr = {
02227 .sin = &s->session->sin,
02228 .transport = mansession_get_transport(s),
02229 },
02230 .common.session_id = session_id,
02231 };
02232
02233 snprintf(session_id, sizeof(session_id), "%p", s->session);
02234
02235 ast_security_event_report(AST_SEC_EVT(&session_limit));
02236 }
02237
02238
02239
02240
02241
02242
02243
02244
02245 static int authenticate(struct mansession *s, const struct message *m)
02246 {
02247 const char *username = astman_get_header(m, "Username");
02248 const char *password = astman_get_header(m, "Secret");
02249 int error = -1;
02250 struct ast_manager_user *user = NULL;
02251 regex_t *regex_filter;
02252 struct ao2_iterator filter_iter;
02253 struct ast_sockaddr addr;
02254
02255 if (ast_strlen_zero(username)) {
02256 return -1;
02257 }
02258
02259
02260 AST_RWLIST_WRLOCK(&users);
02261
02262 ast_sockaddr_from_sin(&addr, &s->session->sin);
02263
02264 if (!(user = get_manager_by_name_locked(username))) {
02265 report_invalid_user(s, username);
02266 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
02267 } else if (user->ha && !ast_apply_ha(user->ha, &addr)) {
02268 report_failed_acl(s, username);
02269 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
02270 } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
02271 const char *key = astman_get_header(m, "Key");
02272 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
02273 int x;
02274 int len = 0;
02275 char md5key[256] = "";
02276 struct MD5Context md5;
02277 unsigned char digest[16];
02278
02279 MD5Init(&md5);
02280 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
02281 MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
02282 MD5Final(digest, &md5);
02283 for (x = 0; x < 16; x++)
02284 len += sprintf(md5key + len, "%2.2x", digest[x]);
02285 if (!strcmp(md5key, key)) {
02286 error = 0;
02287 } else {
02288 report_failed_challenge_response(s, key, md5key);
02289 }
02290 } else {
02291 ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
02292 S_OR(s->session->challenge, ""));
02293 }
02294 } else if (user->secret) {
02295 if (!strcmp(password, user->secret)) {
02296 error = 0;
02297 } else {
02298 report_inval_password(s, username);
02299 }
02300 }
02301
02302 if (error) {
02303 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
02304 AST_RWLIST_UNLOCK(&users);
02305 return -1;
02306 }
02307
02308
02309
02310
02311
02312
02313 ast_copy_string(s->session->username, username, sizeof(s->session->username));
02314 s->session->readperm = user->readperm;
02315 s->session->writeperm = user->writeperm;
02316 s->session->writetimeout = user->writetimeout;
02317
02318 filter_iter = ao2_iterator_init(user->whitefilters, 0);
02319 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
02320 ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
02321 ao2_t_ref(regex_filter, -1, "remove iterator ref");
02322 }
02323 ao2_iterator_destroy(&filter_iter);
02324
02325 filter_iter = ao2_iterator_init(user->blackfilters, 0);
02326 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
02327 ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
02328 ao2_t_ref(regex_filter, -1, "remove iterator ref");
02329 }
02330 ao2_iterator_destroy(&filter_iter);
02331
02332 s->session->sessionstart = time(NULL);
02333 s->session->sessionstart_tv = ast_tvnow();
02334 set_eventmask(s, astman_get_header(m, "Events"));
02335
02336 report_auth_success(s);
02337
02338 AST_RWLIST_UNLOCK(&users);
02339 return 0;
02340 }
02341
02342 static int action_ping(struct mansession *s, const struct message *m)
02343 {
02344 const char *actionid = astman_get_header(m, "ActionID");
02345 struct timeval now = ast_tvnow();
02346
02347 astman_append(s, "Response: Success\r\n");
02348 if (!ast_strlen_zero(actionid)){
02349 astman_append(s, "ActionID: %s\r\n", actionid);
02350 }
02351 astman_append(
02352 s,
02353 "Ping: Pong\r\n"
02354 "Timestamp: %ld.%06lu\r\n"
02355 "\r\n",
02356 (long) now.tv_sec, (unsigned long) now.tv_usec);
02357 return 0;
02358 }
02359
02360 static int action_getconfig(struct mansession *s, const struct message *m)
02361 {
02362 struct ast_config *cfg;
02363 const char *fn = astman_get_header(m, "Filename");
02364 const char *category = astman_get_header(m, "Category");
02365 int catcount = 0;
02366 int lineno = 0;
02367 char *cur_category = NULL;
02368 struct ast_variable *v;
02369 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02370
02371 if (ast_strlen_zero(fn)) {
02372 astman_send_error(s, m, "Filename not specified");
02373 return 0;
02374 }
02375 cfg = ast_config_load2(fn, "manager", config_flags);
02376 if (cfg == CONFIG_STATUS_FILEMISSING) {
02377 astman_send_error(s, m, "Config file not found");
02378 return 0;
02379 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02380 astman_send_error(s, m, "Config file has invalid format");
02381 return 0;
02382 }
02383
02384 astman_start_ack(s, m);
02385 while ((cur_category = ast_category_browse(cfg, cur_category))) {
02386 if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
02387 lineno = 0;
02388 astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
02389 for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
02390 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
02391 }
02392 catcount++;
02393 }
02394 }
02395 if (!ast_strlen_zero(category) && catcount == 0) {
02396 astman_append(s, "No categories found\r\n");
02397 }
02398 ast_config_destroy(cfg);
02399 astman_append(s, "\r\n");
02400
02401 return 0;
02402 }
02403
02404 static int action_listcategories(struct mansession *s, const struct message *m)
02405 {
02406 struct ast_config *cfg;
02407 const char *fn = astman_get_header(m, "Filename");
02408 char *category = NULL;
02409 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02410 int catcount = 0;
02411
02412 if (ast_strlen_zero(fn)) {
02413 astman_send_error(s, m, "Filename not specified");
02414 return 0;
02415 }
02416 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
02417 astman_send_error(s, m, "Config file not found");
02418 return 0;
02419 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02420 astman_send_error(s, m, "Config file has invalid format");
02421 return 0;
02422 }
02423 astman_start_ack(s, m);
02424 while ((category = ast_category_browse(cfg, category))) {
02425 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
02426 catcount++;
02427 }
02428 if (catcount == 0) {
02429 astman_append(s, "Error: no categories found\r\n");
02430 }
02431 ast_config_destroy(cfg);
02432 astman_append(s, "\r\n");
02433
02434 return 0;
02435 }
02436
02437
02438
02439
02440
02441 static void json_escape(char *out, const char *in)
02442 {
02443 for (; *in; in++) {
02444 if (*in == '\\' || *in == '\"') {
02445 *out++ = '\\';
02446 }
02447 *out++ = *in;
02448 }
02449 *out = '\0';
02450 }
02451
02452 static int action_getconfigjson(struct mansession *s, const struct message *m)
02453 {
02454 struct ast_config *cfg;
02455 const char *fn = astman_get_header(m, "Filename");
02456 char *category = NULL;
02457 struct ast_variable *v;
02458 int comma1 = 0;
02459 char *buf = NULL;
02460 unsigned int buf_len = 0;
02461 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02462
02463 if (ast_strlen_zero(fn)) {
02464 astman_send_error(s, m, "Filename not specified");
02465 return 0;
02466 }
02467
02468 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
02469 astman_send_error(s, m, "Config file not found");
02470 return 0;
02471 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02472 astman_send_error(s, m, "Config file has invalid format");
02473 return 0;
02474 }
02475
02476 buf_len = 512;
02477 buf = alloca(buf_len);
02478
02479 astman_start_ack(s, m);
02480 astman_append(s, "JSON: {");
02481 while ((category = ast_category_browse(cfg, category))) {
02482 int comma2 = 0;
02483 if (buf_len < 2 * strlen(category) + 1) {
02484 buf_len *= 2;
02485 buf = alloca(buf_len);
02486 }
02487 json_escape(buf, category);
02488 astman_append(s, "%s\"%s\":[", comma1 ? "," : "", buf);
02489 if (!comma1) {
02490 comma1 = 1;
02491 }
02492 for (v = ast_variable_browse(cfg, category); v; v = v->next) {
02493 if (comma2) {
02494 astman_append(s, ",");
02495 }
02496 if (buf_len < 2 * strlen(v->name) + 1) {
02497 buf_len *= 2;
02498 buf = alloca(buf_len);
02499 }
02500 json_escape(buf, v->name);
02501 astman_append(s, "\"%s", buf);
02502 if (buf_len < 2 * strlen(v->value) + 1) {
02503 buf_len *= 2;
02504 buf = alloca(buf_len);
02505 }
02506 json_escape(buf, v->value);
02507 astman_append(s, "%s\"", buf);
02508 if (!comma2) {
02509 comma2 = 1;
02510 }
02511 }
02512 astman_append(s, "]");
02513 }
02514 astman_append(s, "}\r\n\r\n");
02515
02516 ast_config_destroy(cfg);
02517
02518 return 0;
02519 }
02520
02521
02522 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
02523 {
02524 int x;
02525 char hdr[40];
02526 const char *action, *cat, *var, *value, *match, *line;
02527 struct ast_category *category;
02528 struct ast_variable *v;
02529 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
02530 enum error_type result = 0;
02531
02532 for (x = 0; x < 100000; x++) {
02533 unsigned int object = 0;
02534
02535 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
02536 action = astman_get_header(m, hdr);
02537 if (ast_strlen_zero(action))
02538 break;
02539
02540 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
02541 cat = astman_get_header(m, hdr);
02542 if (ast_strlen_zero(cat)) {
02543 result = UNSPECIFIED_CATEGORY;
02544 break;
02545 }
02546
02547 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
02548 var = astman_get_header(m, hdr);
02549
02550 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
02551 value = astman_get_header(m, hdr);
02552
02553 if (!ast_strlen_zero(value) && *value == '>') {
02554 object = 1;
02555 value++;
02556 }
02557
02558 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
02559 match = astman_get_header(m, hdr);
02560
02561 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
02562 line = astman_get_header(m, hdr);
02563
02564 if (!strcasecmp(action, "newcat")) {
02565 if (ast_category_get(cfg,cat)) {
02566 result = FAILURE_NEWCAT;
02567 break;
02568 }
02569 if (!(category = ast_category_new(cat, dfn, -1))) {
02570 result = FAILURE_ALLOCATION;
02571 break;
02572 }
02573 if (ast_strlen_zero(match)) {
02574 ast_category_append(cfg, category);
02575 } else {
02576 ast_category_insert(cfg, category, match);
02577 }
02578 } else if (!strcasecmp(action, "renamecat")) {
02579 if (ast_strlen_zero(value)) {
02580 result = UNSPECIFIED_ARGUMENT;
02581 break;
02582 }
02583 if (!(category = ast_category_get(cfg, cat))) {
02584 result = UNKNOWN_CATEGORY;
02585 break;
02586 }
02587 ast_category_rename(category, value);
02588 } else if (!strcasecmp(action, "delcat")) {
02589 if (ast_category_delete(cfg, cat)) {
02590 result = FAILURE_DELCAT;
02591 break;
02592 }
02593 } else if (!strcasecmp(action, "emptycat")) {
02594 if (ast_category_empty(cfg, cat)) {
02595 result = FAILURE_EMPTYCAT;
02596 break;
02597 }
02598 } else if (!strcasecmp(action, "update")) {
02599 if (ast_strlen_zero(var)) {
02600 result = UNSPECIFIED_ARGUMENT;
02601 break;
02602 }
02603 if (!(category = ast_category_get(cfg,cat))) {
02604 result = UNKNOWN_CATEGORY;
02605 break;
02606 }
02607 if (ast_variable_update(category, var, value, match, object)) {
02608 result = FAILURE_UPDATE;
02609 break;
02610 }
02611 } else if (!strcasecmp(action, "delete")) {
02612 if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
02613 result = UNSPECIFIED_ARGUMENT;
02614 break;
02615 }
02616 if (!(category = ast_category_get(cfg, cat))) {
02617 result = UNKNOWN_CATEGORY;
02618 break;
02619 }
02620 if (ast_variable_delete(category, var, match, line)) {
02621 result = FAILURE_DELETE;
02622 break;
02623 }
02624 } else if (!strcasecmp(action, "append")) {
02625 if (ast_strlen_zero(var)) {
02626 result = UNSPECIFIED_ARGUMENT;
02627 break;
02628 }
02629 if (!(category = ast_category_get(cfg, cat))) {
02630 result = UNKNOWN_CATEGORY;
02631 break;
02632 }
02633 if (!(v = ast_variable_new(var, value, dfn))) {
02634 result = FAILURE_ALLOCATION;
02635 break;
02636 }
02637 if (object || (match && !strcasecmp(match, "object"))) {
02638 v->object = 1;
02639 }
02640 ast_variable_append(category, v);
02641 } else if (!strcasecmp(action, "insert")) {
02642 if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
02643 result = UNSPECIFIED_ARGUMENT;
02644 break;
02645 }
02646 if (!(category = ast_category_get(cfg, cat))) {
02647 result = UNKNOWN_CATEGORY;
02648 break;
02649 }
02650 if (!(v = ast_variable_new(var, value, dfn))) {
02651 result = FAILURE_ALLOCATION;
02652 break;
02653 }
02654 ast_variable_insert(category, v, line);
02655 }
02656 else {
02657 ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
02658 result = UNKNOWN_ACTION;
02659 break;
02660 }
02661 }
02662 ast_free(str1);
02663 ast_free(str2);
02664 return result;
02665 }
02666
02667 static int action_updateconfig(struct mansession *s, const struct message *m)
02668 {
02669 struct ast_config *cfg;
02670 const char *sfn = astman_get_header(m, "SrcFilename");
02671 const char *dfn = astman_get_header(m, "DstFilename");
02672 int res;
02673 const char *rld = astman_get_header(m, "Reload");
02674 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02675 enum error_type result;
02676
02677 if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
02678 astman_send_error(s, m, "Filename not specified");
02679 return 0;
02680 }
02681 if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
02682 astman_send_error(s, m, "Config file not found");
02683 return 0;
02684 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02685 astman_send_error(s, m, "Config file has invalid format");
02686 return 0;
02687 }
02688 result = handle_updates(s, m, cfg, dfn);
02689 if (!result) {
02690 ast_include_rename(cfg, sfn, dfn);
02691 res = ast_config_text_file_save(dfn, cfg, "Manager");
02692 ast_config_destroy(cfg);
02693 if (res) {
02694 astman_send_error(s, m, "Save of config failed");
02695 return 0;
02696 }
02697 astman_send_ack(s, m, NULL);
02698 if (!ast_strlen_zero(rld)) {
02699 if (ast_true(rld)) {
02700 rld = NULL;
02701 }
02702 ast_module_reload(rld);
02703 }
02704 } else {
02705 ast_config_destroy(cfg);
02706 switch(result) {
02707 case UNKNOWN_ACTION:
02708 astman_send_error(s, m, "Unknown action command");
02709 break;
02710 case UNKNOWN_CATEGORY:
02711 astman_send_error(s, m, "Given category does not exist");
02712 break;
02713 case UNSPECIFIED_CATEGORY:
02714 astman_send_error(s, m, "Category not specified");
02715 break;
02716 case UNSPECIFIED_ARGUMENT:
02717 astman_send_error(s, m, "Problem with category, value, or line (if required)");
02718 break;
02719 case FAILURE_ALLOCATION:
02720 astman_send_error(s, m, "Memory allocation failure, this should not happen");
02721 break;
02722 case FAILURE_NEWCAT:
02723 astman_send_error(s, m, "Create category did not complete successfully");
02724 break;
02725 case FAILURE_DELCAT:
02726 astman_send_error(s, m, "Delete category did not complete successfully");
02727 break;
02728 case FAILURE_EMPTYCAT:
02729 astman_send_error(s, m, "Empty category did not complete successfully");
02730 break;
02731 case FAILURE_UPDATE:
02732 astman_send_error(s, m, "Update did not complete successfully");
02733 break;
02734 case FAILURE_DELETE:
02735 astman_send_error(s, m, "Delete did not complete successfully");
02736 break;
02737 case FAILURE_APPEND:
02738 astman_send_error(s, m, "Append did not complete successfully");
02739 break;
02740 }
02741 }
02742 return 0;
02743 }
02744
02745 static int action_createconfig(struct mansession *s, const struct message *m)
02746 {
02747 int fd;
02748 const char *fn = astman_get_header(m, "Filename");
02749 struct ast_str *filepath = ast_str_alloca(PATH_MAX);
02750 ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
02751 ast_str_append(&filepath, 0, "%s", fn);
02752
02753 if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
02754 close(fd);
02755 astman_send_ack(s, m, "New configuration file created successfully");
02756 } else {
02757 astman_send_error(s, m, strerror(errno));
02758 }
02759
02760 return 0;
02761 }
02762
02763 static int action_waitevent(struct mansession *s, const struct message *m)
02764 {
02765 const char *timeouts = astman_get_header(m, "Timeout");
02766 int timeout = -1;
02767 int x;
02768 int needexit = 0;
02769 const char *id = astman_get_header(m, "ActionID");
02770 char idText[256];
02771
02772 if (!ast_strlen_zero(id)) {
02773 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02774 } else {
02775 idText[0] = '\0';
02776 }
02777
02778 if (!ast_strlen_zero(timeouts)) {
02779 sscanf(timeouts, "%30i", &timeout);
02780 if (timeout < -1) {
02781 timeout = -1;
02782 }
02783
02784 }
02785
02786 ao2_lock(s->session);
02787 if (s->session->waiting_thread != AST_PTHREADT_NULL) {
02788 pthread_kill(s->session->waiting_thread, SIGURG);
02789 }
02790
02791 if (s->session->managerid) {
02792
02793
02794
02795
02796
02797 time_t now = time(NULL);
02798 int max = s->session->sessiontimeout - now - 10;
02799
02800 if (max < 0) {
02801 max = 0;
02802 }
02803 if (timeout < 0 || timeout > max) {
02804 timeout = max;
02805 }
02806 if (!s->session->send_events) {
02807 s->session->send_events = -1;
02808 }
02809 }
02810 ao2_unlock(s->session);
02811
02812
02813 s->session->waiting_thread = pthread_self();
02814 ast_debug(1, "Starting waiting for an event!\n");
02815
02816 for (x = 0; x < timeout || timeout < 0; x++) {
02817 ao2_lock(s->session);
02818 if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
02819 needexit = 1;
02820 }
02821
02822
02823
02824
02825 if (s->session->waiting_thread != pthread_self()) {
02826 needexit = 1;
02827 }
02828 if (s->session->needdestroy) {
02829 needexit = 1;
02830 }
02831 ao2_unlock(s->session);
02832 if (needexit) {
02833 break;
02834 }
02835 if (s->session->managerid == 0) {
02836 if (ast_wait_for_input(s->session->fd, 1000)) {
02837 break;
02838 }
02839 } else {
02840 sleep(1);
02841 }
02842 }
02843 ast_debug(1, "Finished waiting for an event!\n");
02844
02845 ao2_lock(s->session);
02846 if (s->session->waiting_thread == pthread_self()) {
02847 struct eventqent *eqe = s->session->last_ev;
02848 astman_send_response(s, m, "Success", "Waiting for Event completed.");
02849 while ((eqe = advance_event(eqe))) {
02850 if (((s->session->readperm & eqe->category) == eqe->category) &&
02851 ((s->session->send_events & eqe->category) == eqe->category)) {
02852 astman_append(s, "%s", eqe->eventdata);
02853 }
02854 s->session->last_ev = eqe;
02855 }
02856 astman_append(s,
02857 "Event: WaitEventComplete\r\n"
02858 "%s"
02859 "\r\n", idText);
02860 s->session->waiting_thread = AST_PTHREADT_NULL;
02861 } else {
02862 ast_debug(1, "Abandoning event request!\n");
02863 }
02864 ao2_unlock(s->session);
02865
02866 return 0;
02867 }
02868
02869
02870 static int action_listcommands(struct mansession *s, const struct message *m)
02871 {
02872 struct manager_action *cur;
02873 struct ast_str *temp = ast_str_alloca(BUFSIZ);
02874
02875 astman_start_ack(s, m);
02876 AST_RWLIST_TRAVERSE(&actions, cur, list) {
02877 if (s->session->writeperm & cur->authority || cur->authority == 0) {
02878 astman_append(s, "%s: %s (Priv: %s)\r\n",
02879 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
02880 }
02881 }
02882 astman_append(s, "\r\n");
02883
02884 return 0;
02885 }
02886
02887 static int action_events(struct mansession *s, const struct message *m)
02888 {
02889 const char *mask = astman_get_header(m, "EventMask");
02890 int res, x;
02891
02892 res = set_eventmask(s, mask);
02893 if (broken_events_action) {
02894
02895
02896
02897 if (res > 0) {
02898 for (x = 0; x < ARRAY_LEN(perms); x++) {
02899 if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
02900 return 0;
02901 }
02902 }
02903 astman_append(s, "Response: Success\r\n"
02904 "Events: On\r\n\r\n");
02905 } else if (res == 0)
02906 astman_append(s, "Response: Success\r\n"
02907 "Events: Off\r\n\r\n");
02908 return 0;
02909 }
02910
02911 if (res > 0)
02912 astman_append(s, "Response: Success\r\n"
02913 "Events: On\r\n\r\n");
02914 else if (res == 0)
02915 astman_append(s, "Response: Success\r\n"
02916 "Events: Off\r\n\r\n");
02917 else
02918 astman_send_error(s, m, "Invalid event mask");
02919
02920 return 0;
02921 }
02922
02923 static int action_logoff(struct mansession *s, const struct message *m)
02924 {
02925 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
02926 return -1;
02927 }
02928
02929 static int action_login(struct mansession *s, const struct message *m)
02930 {
02931
02932
02933 if (s->session->authenticated) {
02934 astman_send_ack(s, m, "Already authenticated");
02935 return 0;
02936 }
02937
02938 if (authenticate(s, m)) {
02939 sleep(1);
02940 astman_send_error(s, m, "Authentication failed");
02941 return -1;
02942 }
02943 s->session->authenticated = 1;
02944 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02945 if (manager_displayconnects(s->session)) {
02946 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02947 }
02948 astman_send_ack(s, m, "Authentication accepted");
02949 if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
02950 manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
02951 }
02952 return 0;
02953 }
02954
02955 static int action_challenge(struct mansession *s, const struct message *m)
02956 {
02957 const char *authtype = astman_get_header(m, "AuthType");
02958
02959 if (!strcasecmp(authtype, "MD5")) {
02960 if (ast_strlen_zero(s->session->challenge)) {
02961 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
02962 }
02963 mansession_lock(s);
02964 astman_start_ack(s, m);
02965 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
02966 mansession_unlock(s);
02967 } else {
02968 astman_send_error(s, m, "Must specify AuthType");
02969 }
02970 return 0;
02971 }
02972
02973 static int action_hangup(struct mansession *s, const struct message *m)
02974 {
02975 struct ast_channel *c = NULL;
02976 int causecode = 0;
02977 const char *name = astman_get_header(m, "Channel");
02978 const char *cause = astman_get_header(m, "Cause");
02979
02980 if (ast_strlen_zero(name)) {
02981 astman_send_error(s, m, "No channel specified");
02982 return 0;
02983 }
02984
02985 if (!ast_strlen_zero(cause)) {
02986 char *endptr;
02987 causecode = strtol(cause, &endptr, 10);
02988 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
02989 ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
02990
02991 causecode = 0;
02992 }
02993 }
02994
02995 if (!(c = ast_channel_get_by_name(name))) {
02996 astman_send_error(s, m, "No such channel");
02997 return 0;
02998 }
02999
03000 ast_channel_lock(c);
03001 if (causecode > 0) {
03002 ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
03003 c->name, causecode, c->hangupcause);
03004 c->hangupcause = causecode;
03005 }
03006 ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
03007 ast_channel_unlock(c);
03008
03009 c = ast_channel_unref(c);
03010
03011 astman_send_ack(s, m, "Channel Hungup");
03012
03013 return 0;
03014 }
03015
03016 static int action_setvar(struct mansession *s, const struct message *m)
03017 {
03018 struct ast_channel *c = NULL;
03019 const char *name = astman_get_header(m, "Channel");
03020 const char *varname = astman_get_header(m, "Variable");
03021 const char *varval = astman_get_header(m, "Value");
03022 int res = 0;
03023
03024 if (ast_strlen_zero(varname)) {
03025 astman_send_error(s, m, "No variable specified");
03026 return 0;
03027 }
03028
03029 if (!ast_strlen_zero(name)) {
03030 if (!(c = ast_channel_get_by_name(name))) {
03031 astman_send_error(s, m, "No such channel");
03032 return 0;
03033 }
03034 }
03035
03036 res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
03037
03038 if (c) {
03039 c = ast_channel_unref(c);
03040 }
03041 if (res == 0) {
03042 astman_send_ack(s, m, "Variable Set");
03043 } else {
03044 astman_send_error(s, m, "Variable not set");
03045 }
03046 return 0;
03047 }
03048
03049 static int action_getvar(struct mansession *s, const struct message *m)
03050 {
03051 struct ast_channel *c = NULL;
03052 const char *name = astman_get_header(m, "Channel");
03053 const char *varname = astman_get_header(m, "Variable");
03054 char *varval;
03055 char workspace[1024] = "";
03056
03057 if (ast_strlen_zero(varname)) {
03058 astman_send_error(s, m, "No variable specified");
03059 return 0;
03060 }
03061
03062 if (!ast_strlen_zero(name)) {
03063 if (!(c = ast_channel_get_by_name(name))) {
03064 astman_send_error(s, m, "No such channel");
03065 return 0;
03066 }
03067 }
03068
03069 if (varname[strlen(varname) - 1] == ')') {
03070 if (!c) {
03071 c = ast_dummy_channel_alloc();
03072 if (c) {
03073 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
03074 c = ast_channel_release(c);
03075 } else
03076 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
03077 } else {
03078 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
03079 }
03080 varval = workspace;
03081 } else {
03082 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
03083 }
03084
03085 if (c) {
03086 c = ast_channel_unref(c);
03087 }
03088
03089 astman_start_ack(s, m);
03090 astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
03091
03092 return 0;
03093 }
03094
03095
03096
03097 static int action_status(struct mansession *s, const struct message *m)
03098 {
03099 const char *name = astman_get_header(m, "Channel");
03100 const char *cvariables = astman_get_header(m, "Variables");
03101 char *variables = ast_strdupa(S_OR(cvariables, ""));
03102 struct ast_channel *c;
03103 char bridge[256];
03104 struct timeval now = ast_tvnow();
03105 long elapsed_seconds = 0;
03106 int channels = 0;
03107 int all = ast_strlen_zero(name);
03108 const char *id = astman_get_header(m, "ActionID");
03109 char idText[256];
03110 AST_DECLARE_APP_ARGS(vars,
03111 AST_APP_ARG(name)[100];
03112 );
03113 struct ast_str *str = ast_str_create(1000);
03114 struct ast_channel_iterator *iter = NULL;
03115
03116 if (!ast_strlen_zero(id)) {
03117 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03118 } else {
03119 idText[0] = '\0';
03120 }
03121
03122 if (all) {
03123 if (!(iter = ast_channel_iterator_all_new())) {
03124 ast_free(str);
03125 astman_send_error(s, m, "Memory Allocation Failure");
03126 return 1;
03127 }
03128 c = ast_channel_iterator_next(iter);
03129 } else {
03130 if (!(c = ast_channel_get_by_name(name))) {
03131 astman_send_error(s, m, "No such channel");
03132 ast_free(str);
03133 return 0;
03134 }
03135 }
03136
03137 astman_send_ack(s, m, "Channel status will follow");
03138
03139 if (!ast_strlen_zero(cvariables)) {
03140 AST_STANDARD_APP_ARGS(vars, variables);
03141 }
03142
03143
03144 for (; c; c = ast_channel_iterator_next(iter)) {
03145 ast_channel_lock(c);
03146
03147 if (!ast_strlen_zero(cvariables)) {
03148 int i;
03149 ast_str_reset(str);
03150 for (i = 0; i < vars.argc; i++) {
03151 char valbuf[512], *ret = NULL;
03152
03153 if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
03154 if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
03155 valbuf[0] = '\0';
03156 }
03157 ret = valbuf;
03158 } else {
03159 pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
03160 }
03161
03162 ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
03163 }
03164 }
03165
03166 channels++;
03167 if (c->_bridge) {
03168 snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", c->_bridge->name, c->_bridge->uniqueid);
03169 } else {
03170 bridge[0] = '\0';
03171 }
03172 if (c->pbx) {
03173 if (c->cdr) {
03174 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
03175 }
03176 astman_append(s,
03177 "Event: Status\r\n"
03178 "Privilege: Call\r\n"
03179 "Channel: %s\r\n"
03180 "CallerIDNum: %s\r\n"
03181 "CallerIDName: %s\r\n"
03182 "Accountcode: %s\r\n"
03183 "ChannelState: %d\r\n"
03184 "ChannelStateDesc: %s\r\n"
03185 "Context: %s\r\n"
03186 "Extension: %s\r\n"
03187 "Priority: %d\r\n"
03188 "Seconds: %ld\r\n"
03189 "%s"
03190 "Uniqueid: %s\r\n"
03191 "%s"
03192 "%s"
03193 "\r\n",
03194 c->name,
03195 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
03196 S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
03197 c->accountcode,
03198 c->_state,
03199 ast_state2str(c->_state), c->context,
03200 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
03201 } else {
03202 astman_append(s,
03203 "Event: Status\r\n"
03204 "Privilege: Call\r\n"
03205 "Channel: %s\r\n"
03206 "CallerIDNum: %s\r\n"
03207 "CallerIDName: %s\r\n"
03208 "Account: %s\r\n"
03209 "State: %s\r\n"
03210 "%s"
03211 "Uniqueid: %s\r\n"
03212 "%s"
03213 "%s"
03214 "\r\n",
03215 c->name,
03216 S_COR(c->caller.id.number.valid, c->caller.id.number.str, "<unknown>"),
03217 S_COR(c->caller.id.name.valid, c->caller.id.name.str, "<unknown>"),
03218 c->accountcode,
03219 ast_state2str(c->_state), bridge, c->uniqueid,
03220 ast_str_buffer(str), idText);
03221 }
03222
03223 ast_channel_unlock(c);
03224 c = ast_channel_unref(c);
03225
03226 if (!all) {
03227 break;
03228 }
03229 }
03230
03231 if (iter) {
03232 ast_channel_iterator_destroy(iter);
03233 }
03234
03235 astman_append(s,
03236 "Event: StatusComplete\r\n"
03237 "%s"
03238 "Items: %d\r\n"
03239 "\r\n", idText, channels);
03240
03241 ast_free(str);
03242
03243 return 0;
03244 }
03245
03246 static int action_sendtext(struct mansession *s, const struct message *m)
03247 {
03248 struct ast_channel *c = NULL;
03249 const char *name = astman_get_header(m, "Channel");
03250 const char *textmsg = astman_get_header(m, "Message");
03251 int res = 0;
03252
03253 if (ast_strlen_zero(name)) {
03254 astman_send_error(s, m, "No channel specified");
03255 return 0;
03256 }
03257
03258 if (ast_strlen_zero(textmsg)) {
03259 astman_send_error(s, m, "No Message specified");
03260 return 0;
03261 }
03262
03263 if (!(c = ast_channel_get_by_name(name))) {
03264 astman_send_error(s, m, "No such channel");
03265 return 0;
03266 }
03267
03268 ast_channel_lock(c);
03269 res = ast_sendtext(c, textmsg);
03270 ast_channel_unlock(c);
03271 c = ast_channel_unref(c);
03272
03273 if (res > 0) {
03274 astman_send_ack(s, m, "Success");
03275 } else {
03276 astman_send_error(s, m, "Failure");
03277 }
03278
03279 return res;
03280 }
03281
03282
03283 static int action_redirect(struct mansession *s, const struct message *m)
03284 {
03285 const char *name = astman_get_header(m, "Channel");
03286 const char *name2 = astman_get_header(m, "ExtraChannel");
03287 const char *exten = astman_get_header(m, "Exten");
03288 const char *exten2 = astman_get_header(m, "ExtraExten");
03289 const char *context = astman_get_header(m, "Context");
03290 const char *context2 = astman_get_header(m, "ExtraContext");
03291 const char *priority = astman_get_header(m, "Priority");
03292 const char *priority2 = astman_get_header(m, "ExtraPriority");
03293 struct ast_channel *chan, *chan2 = NULL;
03294 int pi, pi2 = 0;
03295 int res;
03296
03297 if (ast_strlen_zero(name)) {
03298 astman_send_error(s, m, "Channel not specified");
03299 return 0;
03300 }
03301
03302 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
03303 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
03304 astman_send_error(s, m, "Invalid priority");
03305 return 0;
03306 }
03307 }
03308
03309 if (!ast_strlen_zero(priority2) && (sscanf(priority2, "%30d", &pi2) != 1)) {
03310 if ((pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL)) < 1) {
03311 astman_send_error(s, m, "Invalid ExtraPriority");
03312 return 0;
03313 }
03314 }
03315
03316 if (!(chan = ast_channel_get_by_name(name))) {
03317 char buf[256];
03318 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
03319 astman_send_error(s, m, buf);
03320 return 0;
03321 }
03322
03323 if (ast_check_hangup_locked(chan)) {
03324 astman_send_error(s, m, "Redirect failed, channel not up.");
03325 chan = ast_channel_unref(chan);
03326 return 0;
03327 }
03328
03329 if (!ast_strlen_zero(name2)) {
03330 chan2 = ast_channel_get_by_name(name2);
03331 }
03332
03333 if (chan2 && ast_check_hangup_locked(chan2)) {
03334 astman_send_error(s, m, "Redirect failed, extra channel not up.");
03335 chan = ast_channel_unref(chan);
03336 chan2 = ast_channel_unref(chan2);
03337 return 0;
03338 }
03339
03340 if (chan->pbx) {
03341 ast_channel_lock(chan);
03342 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
03343 ast_channel_unlock(chan);
03344 }
03345
03346 res = ast_async_goto(chan, context, exten, pi);
03347 if (!res) {
03348 if (!ast_strlen_zero(name2)) {
03349 if (chan2) {
03350 if (chan2->pbx) {
03351 ast_channel_lock(chan2);
03352 ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT);
03353 ast_channel_unlock(chan2);
03354 }
03355 if (context2) {
03356 res = ast_async_goto(chan2, context2, exten2, pi2);
03357 } else {
03358 res = ast_async_goto(chan2, context, exten, pi);
03359 }
03360 } else {
03361 res = -1;
03362 }
03363 if (!res) {
03364 astman_send_ack(s, m, "Dual Redirect successful");
03365 } else {
03366 astman_send_error(s, m, "Secondary redirect failed");
03367 }
03368 } else {
03369 astman_send_ack(s, m, "Redirect successful");
03370 }
03371 } else {
03372 astman_send_error(s, m, "Redirect failed");
03373 }
03374
03375 if (chan) {
03376 chan = ast_channel_unref(chan);
03377 }
03378
03379 if (chan2) {
03380 chan2 = ast_channel_unref(chan2);
03381 }
03382
03383 return 0;
03384 }
03385
03386 static int action_atxfer(struct mansession *s, const struct message *m)
03387 {
03388 const char *name = astman_get_header(m, "Channel");
03389 const char *exten = astman_get_header(m, "Exten");
03390 const char *context = astman_get_header(m, "Context");
03391 struct ast_channel *chan = NULL;
03392 struct ast_call_feature *atxfer_feature = NULL;
03393 char *feature_code = NULL;
03394
03395 if (ast_strlen_zero(name)) {
03396 astman_send_error(s, m, "No channel specified");
03397 return 0;
03398 }
03399 if (ast_strlen_zero(exten)) {
03400 astman_send_error(s, m, "No extension specified");
03401 return 0;
03402 }
03403
03404 if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
03405 astman_send_error(s, m, "No attended transfer feature found");
03406 return 0;
03407 }
03408
03409 if (!(chan = ast_channel_get_by_name(name))) {
03410 astman_send_error(s, m, "Channel specified does not exist");
03411 return 0;
03412 }
03413
03414 if (!ast_strlen_zero(context)) {
03415 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
03416 }
03417
03418 for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
03419 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
03420 ast_queue_frame(chan, &f);
03421 }
03422
03423 for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
03424 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
03425 ast_queue_frame(chan, &f);
03426 }
03427
03428 chan = ast_channel_unref(chan);
03429
03430 astman_send_ack(s, m, "Atxfer successfully queued");
03431
03432 return 0;
03433 }
03434
03435 static int check_blacklist(const char *cmd)
03436 {
03437 char *cmd_copy, *cur_cmd;
03438 char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
03439 int i;
03440
03441 cmd_copy = ast_strdupa(cmd);
03442 for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
03443 cur_cmd = ast_strip(cur_cmd);
03444 if (ast_strlen_zero(cur_cmd)) {
03445 i--;
03446 continue;
03447 }
03448
03449 cmd_words[i] = cur_cmd;
03450 }
03451
03452 for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
03453 int j, match = 1;
03454
03455 for (j = 0; command_blacklist[i].words[j]; j++) {
03456 if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
03457 match = 0;
03458 break;
03459 }
03460 }
03461
03462 if (match) {
03463 return 1;
03464 }
03465 }
03466
03467 return 0;
03468 }
03469
03470
03471 static int action_command(struct mansession *s, const struct message *m)
03472 {
03473 const char *cmd = astman_get_header(m, "Command");
03474 const char *id = astman_get_header(m, "ActionID");
03475 char *buf, *final_buf;
03476 char template[] = "/tmp/ast-ami-XXXXXX";
03477 int fd;
03478 off_t l;
03479
03480 if (ast_strlen_zero(cmd)) {
03481 astman_send_error(s, m, "No command provided");
03482 return 0;
03483 }
03484
03485 if (check_blacklist(cmd)) {
03486 astman_send_error(s, m, "Command blacklisted");
03487 return 0;
03488 }
03489
03490 fd = mkstemp(template);
03491
03492 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
03493 if (!ast_strlen_zero(id)) {
03494 astman_append(s, "ActionID: %s\r\n", id);
03495 }
03496
03497 ast_cli_command(fd, cmd);
03498 l = lseek(fd, 0, SEEK_END);
03499
03500
03501 buf = ast_calloc(1, l + 1);
03502 final_buf = ast_calloc(1, l + 1);
03503 if (buf) {
03504 lseek(fd, 0, SEEK_SET);
03505 if (read(fd, buf, l) < 0) {
03506 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
03507 }
03508 buf[l] = '\0';
03509 if (final_buf) {
03510 term_strip(final_buf, buf, l);
03511 final_buf[l] = '\0';
03512 }
03513 astman_append(s, "%s", S_OR(final_buf, buf));
03514 ast_free(buf);
03515 }
03516 close(fd);
03517 unlink(template);
03518 astman_append(s, "--END COMMAND--\r\n\r\n");
03519 if (final_buf) {
03520 ast_free(final_buf);
03521 }
03522 return 0;
03523 }
03524
03525
03526 struct fast_originate_helper {
03527 char tech[AST_MAX_EXTENSION];
03528
03529 char data[512];
03530 int timeout;
03531 format_t format;
03532 char app[AST_MAX_APP];
03533 char appdata[AST_MAX_EXTENSION];
03534 char cid_name[AST_MAX_EXTENSION];
03535 char cid_num[AST_MAX_EXTENSION];
03536 char context[AST_MAX_CONTEXT];
03537 char exten[AST_MAX_EXTENSION];
03538 char idtext[AST_MAX_EXTENSION];
03539 char account[AST_MAX_ACCOUNT_CODE];
03540 int priority;
03541 struct ast_variable *vars;
03542 };
03543
03544 static void *fast_originate(void *data)
03545 {
03546 struct fast_originate_helper *in = data;
03547 int res;
03548 int reason = 0;
03549 struct ast_channel *chan = NULL, *chans[1];
03550 char requested_channel[AST_CHANNEL_NAME];
03551
03552 if (!ast_strlen_zero(in->app)) {
03553 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
03554 S_OR(in->cid_num, NULL),
03555 S_OR(in->cid_name, NULL),
03556 in->vars, in->account, &chan);
03557 } else {
03558 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
03559 S_OR(in->cid_num, NULL),
03560 S_OR(in->cid_name, NULL),
03561 in->vars, in->account, &chan);
03562 }
03563
03564 if (!chan) {
03565 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
03566 }
03567
03568 chans[0] = chan;
03569 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
03570 "%s%s"
03571 "Response: %s\r\n"
03572 "Channel: %s\r\n"
03573 "Context: %s\r\n"
03574 "Exten: %s\r\n"
03575 "Reason: %d\r\n"
03576 "Uniqueid: %s\r\n"
03577 "CallerIDNum: %s\r\n"
03578 "CallerIDName: %s\r\n",
03579 in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
03580 chan ? chan->name : requested_channel, in->context, in->exten, reason,
03581 chan ? chan->uniqueid : "<null>",
03582 S_OR(in->cid_num, "<unknown>"),
03583 S_OR(in->cid_name, "<unknown>")
03584 );
03585
03586
03587 if (chan) {
03588 ast_channel_unlock(chan);
03589 }
03590 ast_free(in);
03591 return NULL;
03592 }
03593
03594 static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
03595 {
03596 const char *unitamount;
03597 const char *unittype;
03598 struct ast_str *str = ast_str_alloca(32);
03599
03600 memset(entry, 0, sizeof(*entry));
03601
03602 ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
03603 unitamount = astman_get_header(m, ast_str_buffer(str));
03604
03605 ast_str_set(&str, 0, "UnitType(%u)", entry_num);
03606 unittype = astman_get_header(m, ast_str_buffer(str));
03607
03608 if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
03609 entry->valid_amount = 1;
03610 }
03611
03612 if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
03613 entry->valid_type = 1;
03614 }
03615
03616 return 0;
03617 }
03618
03619 static int action_aocmessage(struct mansession *s, const struct message *m)
03620 {
03621 const char *channel = astman_get_header(m, "Channel");
03622 const char *pchannel = astman_get_header(m, "ChannelPrefix");
03623 const char *msgtype = astman_get_header(m, "MsgType");
03624 const char *chargetype = astman_get_header(m, "ChargeType");
03625 const char *currencyname = astman_get_header(m, "CurrencyName");
03626 const char *currencyamount = astman_get_header(m, "CurrencyAmount");
03627 const char *mult = astman_get_header(m, "CurrencyMultiplier");
03628 const char *totaltype = astman_get_header(m, "TotalType");
03629 const char *aocbillingid = astman_get_header(m, "AOCBillingId");
03630 const char *association_id= astman_get_header(m, "ChargingAssociationId");
03631 const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
03632 const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
03633
03634 enum ast_aoc_type _msgtype;
03635 enum ast_aoc_charge_type _chargetype;
03636 enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
03637 enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
03638 enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
03639 unsigned int _currencyamount = 0;
03640 int _association_id = 0;
03641 unsigned int _association_plan = 0;
03642 struct ast_channel *chan = NULL;
03643
03644 struct ast_aoc_decoded *decoded = NULL;
03645 struct ast_aoc_encoded *encoded = NULL;
03646 size_t encoded_size = 0;
03647
03648 if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
03649 astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
03650 goto aocmessage_cleanup;
03651 }
03652
03653 if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
03654 chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
03655 }
03656
03657 if (!chan) {
03658 astman_send_error(s, m, "No such channel");
03659 goto aocmessage_cleanup;
03660 }
03661
03662 if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
03663 astman_send_error(s, m, "Invalid MsgType");
03664 goto aocmessage_cleanup;
03665 }
03666
03667 if (ast_strlen_zero(chargetype)) {
03668 astman_send_error(s, m, "ChargeType not specified");
03669 goto aocmessage_cleanup;
03670 }
03671
03672 _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
03673
03674 if (!strcasecmp(chargetype, "NA")) {
03675 _chargetype = AST_AOC_CHARGE_NA;
03676 } else if (!strcasecmp(chargetype, "Free")) {
03677 _chargetype = AST_AOC_CHARGE_FREE;
03678 } else if (!strcasecmp(chargetype, "Currency")) {
03679 _chargetype = AST_AOC_CHARGE_CURRENCY;
03680 } else if (!strcasecmp(chargetype, "Unit")) {
03681 _chargetype = AST_AOC_CHARGE_UNIT;
03682 } else {
03683 astman_send_error(s, m, "Invalid ChargeType");
03684 goto aocmessage_cleanup;
03685 }
03686
03687 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
03688
03689 if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
03690 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
03691 goto aocmessage_cleanup;
03692 }
03693
03694 if (ast_strlen_zero(mult)) {
03695 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
03696 goto aocmessage_cleanup;
03697 } else if (!strcasecmp(mult, "onethousandth")) {
03698 _mult = AST_AOC_MULT_ONETHOUSANDTH;
03699 } else if (!strcasecmp(mult, "onehundredth")) {
03700 _mult = AST_AOC_MULT_ONEHUNDREDTH;
03701 } else if (!strcasecmp(mult, "onetenth")) {
03702 _mult = AST_AOC_MULT_ONETENTH;
03703 } else if (!strcasecmp(mult, "one")) {
03704 _mult = AST_AOC_MULT_ONE;
03705 } else if (!strcasecmp(mult, "ten")) {
03706 _mult = AST_AOC_MULT_TEN;
03707 } else if (!strcasecmp(mult, "hundred")) {
03708 _mult = AST_AOC_MULT_HUNDRED;
03709 } else if (!strcasecmp(mult, "thousand")) {
03710 _mult = AST_AOC_MULT_THOUSAND;
03711 } else {
03712 astman_send_error(s, m, "Invalid ChargeMultiplier");
03713 goto aocmessage_cleanup;
03714 }
03715 }
03716
03717
03718 if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
03719 astman_send_error(s, m, "Message Creation Failed");
03720 goto aocmessage_cleanup;
03721 }
03722
03723 if (_msgtype == AST_AOC_D) {
03724 if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
03725 _totaltype = AST_AOC_SUBTOTAL;
03726 }
03727
03728 if (ast_strlen_zero(aocbillingid)) {
03729
03730 } else if (!strcasecmp(aocbillingid, "Normal")) {
03731 _billingid = AST_AOC_BILLING_NORMAL;
03732 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
03733 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
03734 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
03735 _billingid = AST_AOC_BILLING_CREDIT_CARD;
03736 } else {
03737 astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
03738 goto aocmessage_cleanup;
03739 }
03740 } else {
03741 if (ast_strlen_zero(aocbillingid)) {
03742
03743 } else if (!strcasecmp(aocbillingid, "Normal")) {
03744 _billingid = AST_AOC_BILLING_NORMAL;
03745 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
03746 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
03747 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
03748 _billingid = AST_AOC_BILLING_CREDIT_CARD;
03749 } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
03750 _billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL;
03751 } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
03752 _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
03753 } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
03754 _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
03755 } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
03756 _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
03757 } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
03758 _billingid = AST_AOC_BILLING_CALL_TRANSFER;
03759 } else {
03760 astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
03761 goto aocmessage_cleanup;
03762 }
03763
03764 if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
03765 astman_send_error(s, m, "Invalid ChargingAssociationId");
03766 goto aocmessage_cleanup;
03767 }
03768 if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
03769 astman_send_error(s, m, "Invalid ChargingAssociationPlan");
03770 goto aocmessage_cleanup;
03771 }
03772
03773 if (_association_id) {
03774 ast_aoc_set_association_id(decoded, _association_id);
03775 } else if (!ast_strlen_zero(association_num)) {
03776 ast_aoc_set_association_number(decoded, association_num, _association_plan);
03777 }
03778 }
03779
03780 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
03781 ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
03782 } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
03783 struct ast_aoc_unit_entry entry;
03784 int i;
03785
03786
03787 for (i = 0; i < 32; i++) {
03788 if (aocmessage_get_unit_entry(m, &entry, i)) {
03789 break;
03790 }
03791
03792 ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
03793 }
03794
03795
03796 if (!i) {
03797 astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
03798 goto aocmessage_cleanup;
03799 }
03800
03801 }
03802
03803 ast_aoc_set_billing_id(decoded, _billingid);
03804 ast_aoc_set_total_type(decoded, _totaltype);
03805
03806
03807 if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
03808 astman_send_ack(s, m, "AOC Message successfully queued on channel");
03809 } else {
03810 astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
03811 }
03812
03813 aocmessage_cleanup:
03814
03815 ast_aoc_destroy_decoded(decoded);
03816 ast_aoc_destroy_encoded(encoded);
03817
03818 if (chan) {
03819 chan = ast_channel_unref(chan);
03820 }
03821 return 0;
03822 }
03823
03824 static int action_originate(struct mansession *s, const struct message *m)
03825 {
03826 const char *name = astman_get_header(m, "Channel");
03827 const char *exten = astman_get_header(m, "Exten");
03828 const char *context = astman_get_header(m, "Context");
03829 const char *priority = astman_get_header(m, "Priority");
03830 const char *timeout = astman_get_header(m, "Timeout");
03831 const char *callerid = astman_get_header(m, "CallerID");
03832 const char *account = astman_get_header(m, "Account");
03833 const char *app = astman_get_header(m, "Application");
03834 const char *appdata = astman_get_header(m, "Data");
03835 const char *async = astman_get_header(m, "Async");
03836 const char *id = astman_get_header(m, "ActionID");
03837 const char *codecs = astman_get_header(m, "Codecs");
03838 struct ast_variable *vars;
03839 char *tech, *data;
03840 char *l = NULL, *n = NULL;
03841 int pi = 0;
03842 int res;
03843 int to = 30000;
03844 int reason = 0;
03845 char tmp[256];
03846 char tmp2[256];
03847 format_t format = AST_FORMAT_SLINEAR;
03848
03849 pthread_t th;
03850 if (ast_strlen_zero(name)) {
03851 astman_send_error(s, m, "Channel not specified");
03852 return 0;
03853 }
03854 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
03855 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
03856 astman_send_error(s, m, "Invalid priority");
03857 return 0;
03858 }
03859 }
03860 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
03861 astman_send_error(s, m, "Invalid timeout");
03862 return 0;
03863 }
03864 ast_copy_string(tmp, name, sizeof(tmp));
03865 tech = tmp;
03866 data = strchr(tmp, '/');
03867 if (!data) {
03868 astman_send_error(s, m, "Invalid channel");
03869 return 0;
03870 }
03871 *data++ = '\0';
03872 ast_copy_string(tmp2, callerid, sizeof(tmp2));
03873 ast_callerid_parse(tmp2, &n, &l);
03874 if (n) {
03875 if (ast_strlen_zero(n)) {
03876 n = NULL;
03877 }
03878 }
03879 if (l) {
03880 ast_shrink_phone_number(l);
03881 if (ast_strlen_zero(l)) {
03882 l = NULL;
03883 }
03884 }
03885 if (!ast_strlen_zero(codecs)) {
03886 format = 0;
03887 ast_parse_allow_disallow(NULL, &format, codecs, 1);
03888 }
03889 if (!ast_strlen_zero(app)) {
03890
03891
03892 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
03893 && (
03894 strcasestr(app, "system") ||
03895
03896 strcasestr(app, "exec") ||
03897
03898 strcasestr(app, "agi") ||
03899
03900 strstr(appdata, "SHELL") ||
03901 strstr(appdata, "EVAL")
03902 )) {
03903 astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
03904 return 0;
03905 }
03906 }
03907
03908 vars = astman_get_variables(m);
03909
03910 if (ast_true(async)) {
03911 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
03912 if (!fast) {
03913 res = -1;
03914 } else {
03915 if (!ast_strlen_zero(id))
03916 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
03917 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
03918 ast_copy_string(fast->data, data, sizeof(fast->data));
03919 ast_copy_string(fast->app, app, sizeof(fast->app));
03920 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
03921 if (l) {
03922 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
03923 }
03924 if (n) {
03925 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
03926 }
03927 fast->vars = vars;
03928 ast_copy_string(fast->context, context, sizeof(fast->context));
03929 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
03930 ast_copy_string(fast->account, account, sizeof(fast->account));
03931 fast->format = format;
03932 fast->timeout = to;
03933 fast->priority = pi;
03934 if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
03935 ast_free(fast);
03936 res = -1;
03937 } else {
03938 res = 0;
03939 }
03940 }
03941 } else if (!ast_strlen_zero(app)) {
03942 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
03943 } else {
03944 if (exten && context && pi) {
03945 res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
03946 } else {
03947 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
03948 if (vars) {
03949 ast_variables_destroy(vars);
03950 }
03951 return 0;
03952 }
03953 }
03954 if (!res) {
03955 astman_send_ack(s, m, "Originate successfully queued");
03956 } else {
03957 astman_send_error(s, m, "Originate failed");
03958 }
03959 return 0;
03960 }
03961
03962 static int action_mailboxstatus(struct mansession *s, const struct message *m)
03963 {
03964 const char *mailbox = astman_get_header(m, "Mailbox");
03965 int ret;
03966
03967 if (ast_strlen_zero(mailbox)) {
03968 astman_send_error(s, m, "Mailbox not specified");
03969 return 0;
03970 }
03971 ret = ast_app_has_voicemail(mailbox, NULL);
03972 astman_start_ack(s, m);
03973 astman_append(s, "Message: Mailbox Status\r\n"
03974 "Mailbox: %s\r\n"
03975 "Waiting: %d\r\n\r\n", mailbox, ret);
03976 return 0;
03977 }
03978
03979 static int action_mailboxcount(struct mansession *s, const struct message *m)
03980 {
03981 const char *mailbox = astman_get_header(m, "Mailbox");
03982 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
03983
03984 if (ast_strlen_zero(mailbox)) {
03985 astman_send_error(s, m, "Mailbox not specified");
03986 return 0;
03987 }
03988 ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
03989 astman_start_ack(s, m);
03990 astman_append(s, "Message: Mailbox Message Count\r\n"
03991 "Mailbox: %s\r\n"
03992 "UrgMessages: %d\r\n"
03993 "NewMessages: %d\r\n"
03994 "OldMessages: %d\r\n"
03995 "\r\n",
03996 mailbox, urgentmsgs, newmsgs, oldmsgs);
03997 return 0;
03998 }
03999
04000 static int action_extensionstate(struct mansession *s, const struct message *m)
04001 {
04002 const char *exten = astman_get_header(m, "Exten");
04003 const char *context = astman_get_header(m, "Context");
04004 char hint[256] = "";
04005 int status;
04006 if (ast_strlen_zero(exten)) {
04007 astman_send_error(s, m, "Extension not specified");
04008 return 0;
04009 }
04010 if (ast_strlen_zero(context)) {
04011 context = "default";
04012 }
04013 status = ast_extension_state(NULL, context, exten);
04014 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
04015 astman_start_ack(s, m);
04016 astman_append(s, "Message: Extension Status\r\n"
04017 "Exten: %s\r\n"
04018 "Context: %s\r\n"
04019 "Hint: %s\r\n"
04020 "Status: %d\r\n\r\n",
04021 exten, context, hint, status);
04022 return 0;
04023 }
04024
04025 static int action_timeout(struct mansession *s, const struct message *m)
04026 {
04027 struct ast_channel *c;
04028 const char *name = astman_get_header(m, "Channel");
04029 double timeout = atof(astman_get_header(m, "Timeout"));
04030 struct timeval when = { timeout, 0 };
04031
04032 if (ast_strlen_zero(name)) {
04033 astman_send_error(s, m, "No channel specified");
04034 return 0;
04035 }
04036
04037 if (!timeout || timeout < 0) {
04038 astman_send_error(s, m, "No timeout specified");
04039 return 0;
04040 }
04041
04042 if (!(c = ast_channel_get_by_name(name))) {
04043 astman_send_error(s, m, "No such channel");
04044 return 0;
04045 }
04046
04047 when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
04048
04049 ast_channel_lock(c);
04050 ast_channel_setwhentohangup_tv(c, when);
04051 ast_channel_unlock(c);
04052 c = ast_channel_unref(c);
04053
04054 astman_send_ack(s, m, "Timeout Set");
04055
04056 return 0;
04057 }
04058
04059 static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04060 {
04061 regex_t *regex_filter = obj;
04062 const char *eventdata = arg;
04063 int *result = data;
04064
04065 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
04066 *result = 1;
04067 return (CMP_MATCH | CMP_STOP);
04068 }
04069
04070 return 0;
04071 }
04072
04073 static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04074 {
04075 regex_t *regex_filter = obj;
04076 const char *eventdata = arg;
04077 int *result = data;
04078
04079 if (regexec(regex_filter, eventdata, 0, NULL, 0)) {
04080 *result = 1;
04081 return (CMP_MATCH | CMP_STOP);
04082 }
04083
04084 return 0;
04085 }
04086
04087 static int match_filter(struct mansession *s, char *eventdata)
04088 {
04089 int result = 0;
04090
04091 ast_debug(3, "Examining event:\n%s\n", eventdata);
04092 if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04093 return 1;
04094 } else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04095
04096 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04097 } else if (!ao2_container_count(s->session->whitefilters) && ao2_container_count(s->session->blackfilters)) {
04098
04099 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04100 } else {
04101
04102 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04103 if (result) {
04104 result = 0;
04105 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04106 }
04107 }
04108
04109 return result;
04110 }
04111
04112
04113
04114
04115
04116
04117 static int process_events(struct mansession *s)
04118 {
04119 int ret = 0;
04120
04121 ao2_lock(s->session);
04122 if (s->session->f != NULL) {
04123 struct eventqent *eqe = s->session->last_ev;
04124
04125 while ((eqe = advance_event(eqe))) {
04126 if (!ret && s->session->authenticated &&
04127 (s->session->readperm & eqe->category) == eqe->category &&
04128 (s->session->send_events & eqe->category) == eqe->category) {
04129 if (match_filter(s, eqe->eventdata)) {
04130 if (send_string(s, eqe->eventdata) < 0)
04131 ret = -1;
04132 }
04133 }
04134 s->session->last_ev = eqe;
04135 }
04136 }
04137 ao2_unlock(s->session);
04138 return ret;
04139 }
04140
04141 static int action_userevent(struct mansession *s, const struct message *m)
04142 {
04143 const char *event = astman_get_header(m, "UserEvent");
04144 struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
04145 int x;
04146
04147 ast_str_reset(body);
04148
04149 for (x = 0; x < m->hdrcount; x++) {
04150 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
04151 ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
04152 }
04153 }
04154
04155 astman_send_ack(s, m, "Event Sent");
04156 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
04157 return 0;
04158 }
04159
04160
04161 static int action_coresettings(struct mansession *s, const struct message *m)
04162 {
04163 const char *actionid = astman_get_header(m, "ActionID");
04164 char idText[150];
04165
04166 if (!ast_strlen_zero(actionid)) {
04167 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04168 } else {
04169 idText[0] = '\0';
04170 }
04171
04172 astman_append(s, "Response: Success\r\n"
04173 "%s"
04174 "AMIversion: %s\r\n"
04175 "AsteriskVersion: %s\r\n"
04176 "SystemName: %s\r\n"
04177 "CoreMaxCalls: %d\r\n"
04178 "CoreMaxLoadAvg: %f\r\n"
04179 "CoreRunUser: %s\r\n"
04180 "CoreRunGroup: %s\r\n"
04181 "CoreMaxFilehandles: %d\r\n"
04182 "CoreRealTimeEnabled: %s\r\n"
04183 "CoreCDRenabled: %s\r\n"
04184 "CoreHTTPenabled: %s\r\n"
04185 "\r\n",
04186 idText,
04187 AMI_VERSION,
04188 ast_get_version(),
04189 ast_config_AST_SYSTEM_NAME,
04190 option_maxcalls,
04191 option_maxload,
04192 ast_config_AST_RUN_USER,
04193 ast_config_AST_RUN_GROUP,
04194 option_maxfiles,
04195 AST_CLI_YESNO(ast_realtime_enabled()),
04196 AST_CLI_YESNO(check_cdr_enabled()),
04197 AST_CLI_YESNO(check_webmanager_enabled())
04198 );
04199 return 0;
04200 }
04201
04202
04203 static int action_corestatus(struct mansession *s, const struct message *m)
04204 {
04205 const char *actionid = astman_get_header(m, "ActionID");
04206 char idText[150];
04207 char startuptime[150], startupdate[150];
04208 char reloadtime[150], reloaddate[150];
04209 struct ast_tm tm;
04210
04211 if (!ast_strlen_zero(actionid)) {
04212 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04213 } else {
04214 idText[0] = '\0';
04215 }
04216
04217 ast_localtime(&ast_startuptime, &tm, NULL);
04218 ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
04219 ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
04220 ast_localtime(&ast_lastreloadtime, &tm, NULL);
04221 ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
04222 ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
04223
04224 astman_append(s, "Response: Success\r\n"
04225 "%s"
04226 "CoreStartupDate: %s\r\n"
04227 "CoreStartupTime: %s\r\n"
04228 "CoreReloadDate: %s\r\n"
04229 "CoreReloadTime: %s\r\n"
04230 "CoreCurrentCalls: %d\r\n"
04231 "\r\n",
04232 idText,
04233 startupdate,
04234 startuptime,
04235 reloaddate,
04236 reloadtime,
04237 ast_active_channels()
04238 );
04239 return 0;
04240 }
04241
04242
04243 static int action_reload(struct mansession *s, const struct message *m)
04244 {
04245 const char *module = astman_get_header(m, "Module");
04246 int res = ast_module_reload(S_OR(module, NULL));
04247
04248 if (res == 2) {
04249 astman_send_ack(s, m, "Module Reloaded");
04250 } else {
04251 astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload");
04252 }
04253 return 0;
04254 }
04255
04256
04257
04258 static int action_coreshowchannels(struct mansession *s, const struct message *m)
04259 {
04260 const char *actionid = astman_get_header(m, "ActionID");
04261 char idText[256];
04262 struct ast_channel *c = NULL;
04263 int numchans = 0;
04264 int duration, durh, durm, durs;
04265 struct ast_channel_iterator *iter;
04266
04267 if (!ast_strlen_zero(actionid)) {
04268 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04269 } else {
04270 idText[0] = '\0';
04271 }
04272
04273 if (!(iter = ast_channel_iterator_all_new())) {
04274 astman_send_error(s, m, "Memory Allocation Failure");
04275 return 1;
04276 }
04277
04278 astman_send_listack(s, m, "Channels will follow", "start");
04279
04280 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
04281 struct ast_channel *bc;
04282 char durbuf[10] = "";
04283
04284 ast_channel_lock(c);
04285
04286 bc = ast_bridged_channel(c);
04287 if (c->cdr && !ast_tvzero(c->cdr->start)) {
04288 duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
04289 durh = duration / 3600;
04290 durm = (duration % 3600) / 60;
04291 durs = duration % 60;
04292 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
04293 }
04294
04295 astman_append(s,
04296 "Event: CoreShowChannel\r\n"
04297 "%s"
04298 "Channel: %s\r\n"
04299 "UniqueID: %s\r\n"
04300 "Context: %s\r\n"
04301 "Extension: %s\r\n"
04302 "Priority: %d\r\n"
04303 "ChannelState: %d\r\n"
04304 "ChannelStateDesc: %s\r\n"
04305 "Application: %s\r\n"
04306 "ApplicationData: %s\r\n"
04307 "CallerIDnum: %s\r\n"
04308 "Duration: %s\r\n"
04309 "AccountCode: %s\r\n"
04310 "BridgedChannel: %s\r\n"
04311 "BridgedUniqueID: %s\r\n"
04312 "\r\n", idText, c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state,
04313 ast_state2str(c->_state), c->appl ? c->appl : "", c->data ? S_OR(c->data, "") : "",
04314 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
04315 durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
04316
04317 ast_channel_unlock(c);
04318
04319 numchans++;
04320 }
04321
04322 astman_append(s,
04323 "Event: CoreShowChannelsComplete\r\n"
04324 "EventList: Complete\r\n"
04325 "ListItems: %d\r\n"
04326 "%s"
04327 "\r\n", numchans, idText);
04328
04329 ast_channel_iterator_destroy(iter);
04330
04331 return 0;
04332 }
04333
04334
04335 static int manager_modulecheck(struct mansession *s, const struct message *m)
04336 {
04337 int res;
04338 const char *module = astman_get_header(m, "Module");
04339 const char *id = astman_get_header(m, "ActionID");
04340 char idText[256];
04341 #if !defined(LOW_MEMORY)
04342 const char *version;
04343 #endif
04344 char filename[PATH_MAX];
04345 char *cut;
04346
04347 ast_copy_string(filename, module, sizeof(filename));
04348 if ((cut = strchr(filename, '.'))) {
04349 *cut = '\0';
04350 } else {
04351 cut = filename + strlen(filename);
04352 }
04353 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
04354 ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
04355 res = ast_module_check(filename);
04356 if (!res) {
04357 astman_send_error(s, m, "Module not loaded");
04358 return 0;
04359 }
04360 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
04361 ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
04362 #if !defined(LOW_MEMORY)
04363 version = ast_file_version_find(filename);
04364 #endif
04365
04366 if (!ast_strlen_zero(id)) {
04367 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04368 } else {
04369 idText[0] = '\0';
04370 }
04371 astman_append(s, "Response: Success\r\n%s", idText);
04372 #if !defined(LOW_MEMORY)
04373 astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
04374 #endif
04375 return 0;
04376 }
04377
04378 static int manager_moduleload(struct mansession *s, const struct message *m)
04379 {
04380 int res;
04381 const char *module = astman_get_header(m, "Module");
04382 const char *loadtype = astman_get_header(m, "LoadType");
04383
04384 if (!loadtype || strlen(loadtype) == 0) {
04385 astman_send_error(s, m, "Incomplete ModuleLoad action.");
04386 }
04387 if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
04388 astman_send_error(s, m, "Need module name");
04389 }
04390
04391 if (!strcasecmp(loadtype, "load")) {
04392 res = ast_load_resource(module);
04393 if (res) {
04394 astman_send_error(s, m, "Could not load module.");
04395 } else {
04396 astman_send_ack(s, m, "Module loaded.");
04397 }
04398 } else if (!strcasecmp(loadtype, "unload")) {
04399 res = ast_unload_resource(module, AST_FORCE_SOFT);
04400 if (res) {
04401 astman_send_error(s, m, "Could not unload module.");
04402 } else {
04403 astman_send_ack(s, m, "Module unloaded.");
04404 }
04405 } else if (!strcasecmp(loadtype, "reload")) {
04406 if (module != NULL) {
04407 res = ast_module_reload(module);
04408 if (res == 0) {
04409 astman_send_error(s, m, "No such module.");
04410 } else if (res == 1) {
04411 astman_send_error(s, m, "Module does not support reload action.");
04412 } else {
04413 astman_send_ack(s, m, "Module reloaded.");
04414 }
04415 } else {
04416 ast_module_reload(NULL);
04417 astman_send_ack(s, m, "All modules reloaded");
04418 }
04419 } else
04420 astman_send_error(s, m, "Incomplete ModuleLoad action.");
04421 return 0;
04422 }
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437 static int process_message(struct mansession *s, const struct message *m)
04438 {
04439 char action[80] = "";
04440 int ret = 0;
04441 struct manager_action *tmp;
04442 const char *user = astman_get_header(m, "Username");
04443 int (*call_func)(struct mansession *s, const struct message *m) = NULL;
04444
04445 ast_copy_string(action, __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY), sizeof(action));
04446
04447 if (ast_strlen_zero(action)) {
04448 report_req_bad_format(s, "NONE");
04449 mansession_lock(s);
04450 astman_send_error(s, m, "Missing action in request");
04451 mansession_unlock(s);
04452 return 0;
04453 }
04454
04455 if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
04456 if (!s->session->authenticated) {
04457 report_req_not_allowed(s, action);
04458 }
04459 mansession_lock(s);
04460 astman_send_error(s, m, "Permission denied");
04461 mansession_unlock(s);
04462 return 0;
04463 }
04464
04465 if (!allowmultiplelogin && !s->session->authenticated && user &&
04466 (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
04467 if (check_manager_session_inuse(user)) {
04468 report_session_limit(s);
04469 sleep(1);
04470 mansession_lock(s);
04471 astman_send_error(s, m, "Login Already In Use");
04472 mansession_unlock(s);
04473 return -1;
04474 }
04475 }
04476
04477 AST_RWLIST_RDLOCK(&actions);
04478 AST_RWLIST_TRAVERSE(&actions, tmp, list) {
04479 if (strcasecmp(action, tmp->action)) {
04480 continue;
04481 }
04482 if (s->session->writeperm & tmp->authority || tmp->authority == 0) {
04483 call_func = tmp->func;
04484 } else {
04485 astman_send_error(s, m, "Permission denied");
04486 report_req_not_allowed(s, action);
04487 }
04488 break;
04489 }
04490 AST_RWLIST_UNLOCK(&actions);
04491
04492 if (tmp && call_func) {
04493
04494 ast_debug(1, "Running action '%s'\n", tmp->action);
04495 ret = call_func(s, m);
04496 } else {
04497 char buf[512];
04498 if (!tmp) {
04499 report_req_bad_format(s, action);
04500 }
04501 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
04502 mansession_lock(s);
04503 astman_send_error(s, m, buf);
04504 mansession_unlock(s);
04505 }
04506 if (ret) {
04507 return ret;
04508 }
04509
04510
04511
04512 if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
04513 return process_events(s);
04514 } else {
04515 return ret;
04516 }
04517 }
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528 static int get_input(struct mansession *s, char *output)
04529 {
04530 int res, x;
04531 int maxlen = sizeof(s->session->inbuf) - 1;
04532 char *src = s->session->inbuf;
04533 int timeout = -1;
04534 time_t now;
04535
04536
04537
04538
04539
04540 for (x = 0; x < s->session->inlen; x++) {
04541 int cr;
04542 if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
04543 cr = 2;
04544 } else if (src[x] == '\n') {
04545 cr = 1;
04546 } else {
04547 continue;
04548 }
04549 memmove(output, src, x);
04550 output[x] = '\0';
04551 x += cr;
04552 s->session->inlen -= x;
04553 memmove(src, src + x, s->session->inlen);
04554 return 1;
04555 }
04556 if (s->session->inlen >= maxlen) {
04557
04558 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->session->sin.sin_addr), src);
04559 s->session->inlen = 0;
04560 }
04561 res = 0;
04562 while (res == 0) {
04563
04564 if (!s->session->authenticated) {
04565 if(time(&now) == -1) {
04566 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
04567 return -1;
04568 }
04569
04570 timeout = (authtimeout - (now - s->session->authstart)) * 1000;
04571 if (timeout < 0) {
04572
04573 return 0;
04574 }
04575 }
04576
04577 ao2_lock(s->session);
04578 if (s->session->pending_event) {
04579 s->session->pending_event = 0;
04580 ao2_unlock(s->session);
04581 return 0;
04582 }
04583 s->session->waiting_thread = pthread_self();
04584 ao2_unlock(s->session);
04585
04586 res = ast_wait_for_input(s->session->fd, timeout);
04587
04588 ao2_lock(s->session);
04589 s->session->waiting_thread = AST_PTHREADT_NULL;
04590 ao2_unlock(s->session);
04591 }
04592 if (res < 0) {
04593
04594
04595
04596 if (errno == EINTR || errno == EAGAIN) {
04597 return 0;
04598 }
04599 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
04600 return -1;
04601 }
04602
04603 ao2_lock(s->session);
04604 res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
04605 if (res < 1) {
04606 res = -1;
04607 } else {
04608 s->session->inlen += res;
04609 src[s->session->inlen] = '\0';
04610 res = 0;
04611 }
04612 ao2_unlock(s->session);
04613 return res;
04614 }
04615
04616 static int do_message(struct mansession *s)
04617 {
04618 struct message m = { 0 };
04619 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
04620 int res;
04621 time_t now;
04622
04623 for (;;) {
04624
04625 if (process_events(s)) {
04626 return -1;
04627 }
04628 res = get_input(s, header_buf);
04629 if (res == 0) {
04630 if (!s->session->authenticated) {
04631 if(time(&now) == -1) {
04632 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
04633 return -1;
04634 }
04635
04636 if (now - s->session->authstart > authtimeout) {
04637 if (displayconnects) {
04638 ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_inet_ntoa(s->session->sin.sin_addr), authtimeout);
04639 }
04640 return -1;
04641 }
04642 }
04643 continue;
04644 } else if (res > 0) {
04645 if (ast_strlen_zero(header_buf)) {
04646 return process_message(s, &m) ? -1 : 0;
04647 } else if (m.hdrcount < (AST_MAX_MANHEADERS - 1)) {
04648 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
04649 }
04650 } else {
04651 return res;
04652 }
04653 }
04654 }
04655
04656
04657
04658
04659
04660
04661
04662
04663
04664 static void *session_do(void *data)
04665 {
04666 struct ast_tcptls_session_instance *ser = data;
04667 struct mansession_session *session;
04668 struct mansession s = {
04669 .tcptls_session = data,
04670 };
04671 int flags;
04672 int res;
04673 struct sockaddr_in ser_remote_address_tmp;
04674 struct protoent *p;
04675
04676 if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
04677 fclose(ser->f);
04678 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04679 goto done;
04680 }
04681
04682 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
04683 session = build_mansession(ser_remote_address_tmp);
04684
04685 if (session == NULL) {
04686 fclose(ser->f);
04687 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04688 goto done;
04689 }
04690
04691
04692
04693
04694 p = getprotobyname("tcp");
04695 if (p) {
04696 int arg = 1;
04697 if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
04698 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno));
04699 }
04700 } else {
04701 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY, getprotobyname(\"tcp\") failed\nSome manager actions may be slow to respond.\n");
04702 }
04703
04704 flags = fcntl(ser->fd, F_GETFL);
04705 if (!block_sockets) {
04706 flags |= O_NONBLOCK;
04707 } else {
04708 flags &= ~O_NONBLOCK;
04709 }
04710 fcntl(ser->fd, F_SETFL, flags);
04711
04712 ao2_lock(session);
04713
04714 session->last_ev = grab_last();
04715
04716 ast_mutex_init(&s.lock);
04717
04718
04719 session->fd = s.fd = ser->fd;
04720 session->f = s.f = ser->f;
04721 session->sin = ser_remote_address_tmp;
04722 s.session = session;
04723
04724 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
04725
04726 if(time(&session->authstart) == -1) {
04727 ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
04728 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04729 ao2_unlock(session);
04730 session_destroy(session);
04731 goto done;
04732 }
04733 ao2_unlock(session);
04734
04735 astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION);
04736 for (;;) {
04737 if ((res = do_message(&s)) < 0 || s.write_error) {
04738 break;
04739 }
04740 }
04741
04742 if (session->authenticated) {
04743 if (manager_displayconnects(session)) {
04744 ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
04745 }
04746 } else {
04747 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04748 if (displayconnects) {
04749 ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
04750 }
04751 }
04752
04753 session_destroy(session);
04754
04755 ast_mutex_destroy(&s.lock);
04756 done:
04757 ao2_ref(ser, -1);
04758 ser = NULL;
04759 return NULL;
04760 }
04761
04762
04763 static void purge_sessions(int n_max)
04764 {
04765 struct mansession_session *session;
04766 time_t now = time(NULL);
04767 struct ao2_iterator i;
04768
04769 i = ao2_iterator_init(sessions, 0);
04770 while ((session = ao2_iterator_next(&i)) && n_max > 0) {
04771 ao2_lock(session);
04772 if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
04773 if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
04774 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
04775 session->username, ast_inet_ntoa(session->sin.sin_addr));
04776 }
04777 ao2_unlock(session);
04778 session_destroy(session);
04779 n_max--;
04780 } else {
04781 ao2_unlock(session);
04782 unref_mansession(session);
04783 }
04784 }
04785 ao2_iterator_destroy(&i);
04786 }
04787
04788
04789
04790
04791
04792 static int append_event(const char *str, int category)
04793 {
04794 struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
04795 static int seq;
04796
04797 if (!tmp) {
04798 return -1;
04799 }
04800
04801
04802 tmp->usecount = 0;
04803 tmp->category = category;
04804 tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
04805 tmp->tv = ast_tvnow();
04806 AST_RWLIST_NEXT(tmp, eq_next) = NULL;
04807 strcpy(tmp->eventdata, str);
04808
04809 AST_RWLIST_WRLOCK(&all_events);
04810 AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
04811 AST_RWLIST_UNLOCK(&all_events);
04812
04813 return 0;
04814 }
04815
04816 AST_THREADSTORAGE(manager_event_funcbuf);
04817
04818 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
04819 {
04820 struct manager_channel_variable *var;
04821 AST_RWLIST_RDLOCK(&channelvars);
04822 AST_LIST_TRAVERSE(&channelvars, var, entry) {
04823 const char *val = "";
04824 if (var->isfunc) {
04825 struct ast_str *res = ast_str_thread_get(&manager_event_funcbuf, 16);
04826 int ret;
04827 if (res && (ret = ast_func_read2(chan, var->name, &res, 0)) == 0) {
04828 val = ast_str_buffer(res);
04829 }
04830 } else {
04831 val = pbx_builtin_getvar_helper(chan, var->name);
04832 }
04833 ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", chan->name, var->name, val ? val : "");
04834 }
04835 AST_RWLIST_UNLOCK(&channelvars);
04836 }
04837
04838
04839 AST_THREADSTORAGE(manager_event_buf);
04840 #define MANAGER_EVENT_BUF_INITSIZE 256
04841
04842 int __ast_manager_event_multichan(int category, const char *event, int chancount, struct
04843 ast_channel **chans, const char *file, int line, const char *func, const char *fmt, ...)
04844 {
04845 struct mansession_session *session;
04846 struct manager_custom_hook *hook;
04847 struct ast_str *auth = ast_str_alloca(80);
04848 const char *cat_str;
04849 va_list ap;
04850 struct timeval now;
04851 struct ast_str *buf;
04852 int i;
04853
04854 if (!(sessions && ao2_container_count(sessions)) && AST_RWLIST_EMPTY(&manager_hooks)) {
04855 return 0;
04856 }
04857
04858 if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) {
04859 return -1;
04860 }
04861
04862 cat_str = authority_to_str(category, &auth);
04863 ast_str_set(&buf, 0,
04864 "Event: %s\r\nPrivilege: %s\r\n",
04865 event, cat_str);
04866
04867 if (timestampevents) {
04868 now = ast_tvnow();
04869 ast_str_append(&buf, 0,
04870 "Timestamp: %ld.%06lu\r\n",
04871 (long)now.tv_sec, (unsigned long) now.tv_usec);
04872 }
04873 if (manager_debug) {
04874 static int seq;
04875 ast_str_append(&buf, 0,
04876 "SequenceNumber: %d\r\n",
04877 ast_atomic_fetchadd_int(&seq, 1));
04878 ast_str_append(&buf, 0,
04879 "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
04880 }
04881
04882 va_start(ap, fmt);
04883 ast_str_append_va(&buf, 0, fmt, ap);
04884 va_end(ap);
04885 for (i = 0; i < chancount; i++) {
04886 append_channel_vars(&buf, chans[i]);
04887 }
04888
04889 ast_str_append(&buf, 0, "\r\n");
04890
04891 append_event(ast_str_buffer(buf), category);
04892
04893
04894 if (sessions) {
04895 struct ao2_iterator i;
04896 i = ao2_iterator_init(sessions, 0);
04897 while ((session = ao2_iterator_next(&i))) {
04898 ao2_lock(session);
04899 if (session->waiting_thread != AST_PTHREADT_NULL) {
04900 pthread_kill(session->waiting_thread, SIGURG);
04901 } else {
04902
04903
04904
04905
04906
04907 session->pending_event = 1;
04908 }
04909 ao2_unlock(session);
04910 unref_mansession(session);
04911 }
04912 ao2_iterator_destroy(&i);
04913 }
04914
04915 if (!AST_RWLIST_EMPTY(&manager_hooks)) {
04916 AST_RWLIST_RDLOCK(&manager_hooks);
04917 AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
04918 hook->helper(category, event, ast_str_buffer(buf));
04919 }
04920 AST_RWLIST_UNLOCK(&manager_hooks);
04921 }
04922
04923 return 0;
04924 }
04925
04926
04927
04928
04929 int ast_manager_unregister(char *action)
04930 {
04931 struct manager_action *cur;
04932 struct timespec tv = { 5, };
04933
04934 if (AST_RWLIST_TIMEDWRLOCK(&actions, &tv)) {
04935 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
04936 return -1;
04937 }
04938 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
04939 if (!strcasecmp(action, cur->action)) {
04940 AST_RWLIST_REMOVE_CURRENT(list);
04941 ast_string_field_free_memory(cur);
04942 ast_free(cur);
04943 ast_verb(2, "Manager unregistered action %s\n", action);
04944 break;
04945 }
04946 }
04947 AST_RWLIST_TRAVERSE_SAFE_END;
04948 AST_RWLIST_UNLOCK(&actions);
04949
04950 return 0;
04951 }
04952
04953 static int manager_state_cb(char *context, char *exten, int state, void *data)
04954 {
04955
04956 char hint[512];
04957 ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
04958
04959 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
04960 return 0;
04961 }
04962
04963 static int ast_manager_register_struct(struct manager_action *act)
04964 {
04965 struct manager_action *cur, *prev = NULL;
04966 struct timespec tv = { 5, };
04967
04968 if (AST_RWLIST_TIMEDWRLOCK(&actions, &tv)) {
04969 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
04970 return -1;
04971 }
04972 AST_RWLIST_TRAVERSE(&actions, cur, list) {
04973 int ret = strcasecmp(cur->action, act->action);
04974 if (ret == 0) {
04975 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
04976 AST_RWLIST_UNLOCK(&actions);
04977 return -1;
04978 }
04979 if (ret > 0) {
04980 prev = cur;
04981 break;
04982 }
04983 }
04984
04985 if (prev) {
04986 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
04987 } else {
04988 AST_RWLIST_INSERT_HEAD(&actions, act, list);
04989 }
04990
04991 ast_verb(2, "Manager registered action %s\n", act->action);
04992
04993 AST_RWLIST_UNLOCK(&actions);
04994
04995 return 0;
04996 }
04997
04998
04999
05000 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
05001 {
05002 struct manager_action *cur = NULL;
05003 #ifdef AST_XML_DOCS
05004 char *tmpxml;
05005 #endif
05006
05007 if (!(cur = ast_calloc_with_stringfields(1, struct manager_action, 128))) {
05008 return -1;
05009 }
05010
05011 cur->action = action;
05012 cur->authority = auth;
05013 cur->func = func;
05014 #ifdef AST_XML_DOCS
05015 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
05016 tmpxml = ast_xmldoc_build_synopsis("manager", action);
05017 ast_string_field_set(cur, synopsis, tmpxml);
05018 ast_free(tmpxml);
05019
05020 tmpxml = ast_xmldoc_build_syntax("manager", action);
05021 ast_string_field_set(cur, syntax, tmpxml);
05022 ast_free(tmpxml);
05023
05024 tmpxml = ast_xmldoc_build_description("manager", action);
05025 ast_string_field_set(cur, description, tmpxml);
05026 ast_free(tmpxml);
05027
05028 tmpxml = ast_xmldoc_build_seealso("manager", action);
05029 ast_string_field_set(cur, seealso, tmpxml);
05030 ast_free(tmpxml);
05031
05032 tmpxml = ast_xmldoc_build_arguments("manager", action);
05033 ast_string_field_set(cur, arguments, tmpxml);
05034 ast_free(tmpxml);
05035
05036 cur->docsrc = AST_XML_DOC;
05037 } else {
05038 #endif
05039 ast_string_field_set(cur, synopsis, synopsis);
05040 ast_string_field_set(cur, description, description);
05041 #ifdef AST_XML_DOCS
05042 cur->docsrc = AST_STATIC_DOC;
05043 }
05044 #endif
05045 if (ast_manager_register_struct(cur)) {
05046 ast_free(cur);
05047 return -1;
05048 }
05049
05050 return 0;
05051 }
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067 enum output_format {
05068 FORMAT_RAW,
05069 FORMAT_HTML,
05070 FORMAT_XML,
05071 };
05072
05073 static const char * const contenttype[] = {
05074 [FORMAT_RAW] = "plain",
05075 [FORMAT_HTML] = "html",
05076 [FORMAT_XML] = "xml",
05077 };
05078
05079
05080
05081
05082
05083
05084 static struct mansession_session *find_session(uint32_t ident, int incinuse)
05085 {
05086 struct mansession_session *session;
05087 struct ao2_iterator i;
05088
05089 if (ident == 0) {
05090 return NULL;
05091 }
05092
05093 i = ao2_iterator_init(sessions, 0);
05094 while ((session = ao2_iterator_next(&i))) {
05095 ao2_lock(session);
05096 if (session->managerid == ident && !session->needdestroy) {
05097 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05098 break;
05099 }
05100 ao2_unlock(session);
05101 unref_mansession(session);
05102 }
05103 ao2_iterator_destroy(&i);
05104
05105 return session;
05106 }
05107
05108
05109
05110
05111
05112
05113
05114
05115
05116
05117 static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
05118 {
05119 struct mansession_session *session;
05120 struct ao2_iterator i;
05121
05122 if (nonce == 0 || username == NULL || stale == NULL) {
05123 return NULL;
05124 }
05125
05126 i = ao2_iterator_init(sessions, 0);
05127 while ((session = ao2_iterator_next(&i))) {
05128 ao2_lock(session);
05129 if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05130 *stale = 0;
05131 break;
05132 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05133 *stale = 1;
05134 break;
05135 }
05136 ao2_unlock(session);
05137 unref_mansession(session);
05138 }
05139 ao2_iterator_destroy(&i);
05140 return session;
05141 }
05142
05143 int astman_is_authed(uint32_t ident)
05144 {
05145 int authed;
05146 struct mansession_session *session;
05147
05148 if (!(session = find_session(ident, 0)))
05149 return 0;
05150
05151 authed = (session->authenticated != 0);
05152
05153 ao2_unlock(session);
05154 unref_mansession(session);
05155
05156 return authed;
05157 }
05158
05159 int astman_verify_session_readpermissions(uint32_t ident, int perm)
05160 {
05161 int result = 0;
05162 struct mansession_session *session;
05163 struct ao2_iterator i;
05164
05165 if (ident == 0) {
05166 return 0;
05167 }
05168
05169 i = ao2_iterator_init(sessions, 0);
05170 while ((session = ao2_iterator_next(&i))) {
05171 ao2_lock(session);
05172 if ((session->managerid == ident) && (session->readperm & perm)) {
05173 result = 1;
05174 ao2_unlock(session);
05175 unref_mansession(session);
05176 break;
05177 }
05178 ao2_unlock(session);
05179 unref_mansession(session);
05180 }
05181 ao2_iterator_destroy(&i);
05182 return result;
05183 }
05184
05185 int astman_verify_session_writepermissions(uint32_t ident, int perm)
05186 {
05187 int result = 0;
05188 struct mansession_session *session;
05189 struct ao2_iterator i;
05190
05191 if (ident == 0) {
05192 return 0;
05193 }
05194
05195 i = ao2_iterator_init(sessions, 0);
05196 while ((session = ao2_iterator_next(&i))) {
05197 ao2_lock(session);
05198 if ((session->managerid == ident) && (session->writeperm & perm)) {
05199 result = 1;
05200 ao2_unlock(session);
05201 unref_mansession(session);
05202 break;
05203 }
05204 ao2_unlock(session);
05205 unref_mansession(session);
05206 }
05207 ao2_iterator_destroy(&i);
05208 return result;
05209 }
05210
05211
05212
05213
05214
05215
05216 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
05217 {
05218
05219 char buf[256];
05220 char *dst = buf;
05221 int space = sizeof(buf);
05222
05223 for ( ; *src || dst != buf ; src++) {
05224 if (*src == '\0' || space < 10) {
05225 *dst++ = '\0';
05226 ast_str_append(out, 0, "%s", buf);
05227 dst = buf;
05228 space = sizeof(buf);
05229 if (*src == '\0') {
05230 break;
05231 }
05232 }
05233
05234 if ( (mode & 2) && !isalnum(*src)) {
05235 *dst++ = '_';
05236 space--;
05237 continue;
05238 }
05239 switch (*src) {
05240 case '<':
05241 strcpy(dst, "<");
05242 dst += 4;
05243 space -= 4;
05244 break;
05245 case '>':
05246 strcpy(dst, ">");
05247 dst += 4;
05248 space -= 4;
05249 break;
05250 case '\"':
05251 strcpy(dst, """);
05252 dst += 6;
05253 space -= 6;
05254 break;
05255 case '\'':
05256 strcpy(dst, "'");
05257 dst += 6;
05258 space -= 6;
05259 break;
05260 case '&':
05261 strcpy(dst, "&");
05262 dst += 5;
05263 space -= 5;
05264 break;
05265
05266 default:
05267 *dst++ = mode ? tolower(*src) : *src;
05268 space--;
05269 }
05270 }
05271 }
05272
05273 struct variable_count {
05274 char *varname;
05275 int count;
05276 };
05277
05278 static int variable_count_hash_fn(const void *vvc, const int flags)
05279 {
05280 const struct variable_count *vc = vvc;
05281
05282 return ast_str_hash(vc->varname);
05283 }
05284
05285 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
05286 {
05287
05288
05289
05290
05291 struct variable_count *vc = obj;
05292 char *str = vstr;
05293 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05294 }
05295
05296
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
05325 {
05326 struct ast_variable *v;
05327 const char *dest = NULL;
05328 char *var, *val;
05329 const char *objtype = NULL;
05330 int in_data = 0;
05331 int inobj = 0;
05332 int xml = (format == FORMAT_XML);
05333 struct variable_count *vc = NULL;
05334 struct ao2_container *vco = NULL;
05335
05336 if (xml) {
05337
05338 for (v = get_vars; v; v = v->next) {
05339 if (!strcasecmp(v->name, "ajaxdest")) {
05340 dest = v->value;
05341 } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05342 objtype = v->value;
05343 }
05344 }
05345 if (ast_strlen_zero(dest)) {
05346 dest = "unknown";
05347 }
05348 if (ast_strlen_zero(objtype)) {
05349 objtype = "generic";
05350 }
05351 }
05352
05353
05354 while (in && *in) {
05355 val = strsep(&in, "\r\n");
05356 if (in && *in == '\n') {
05357 in++;
05358 }
05359 ast_trim_blanks(val);
05360 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05361 if (ast_strlen_zero(val)) {
05362
05363 if (in_data) {
05364
05365 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05366 in_data = 0;
05367 }
05368
05369 if (inobj) {
05370
05371 ast_str_append(out, 0, xml ? " /></response>\n" :
05372 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05373 inobj = 0;
05374 ao2_ref(vco, -1);
05375 vco = NULL;
05376 }
05377 continue;
05378 }
05379
05380 if (!inobj) {
05381
05382 if (xml) {
05383 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05384 }
05385 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05386 inobj = 1;
05387 }
05388
05389 if (in_data) {
05390
05391 xml_copy_escape(out, val, 0);
05392 ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05393 continue;
05394 }
05395
05396
05397 var = strsep(&val, ":");
05398 if (val) {
05399
05400 val = ast_skip_blanks(val);
05401 ast_trim_blanks(var);
05402 } else {
05403
05404 val = var;
05405 var = "Opaque-data";
05406 in_data = 1;
05407 }
05408
05409
05410 ast_str_append(out, 0, xml ? " " : "<tr><td>");
05411 if ((vc = ao2_find(vco, var, 0))) {
05412 vc->count++;
05413 } else {
05414
05415 vc = ao2_alloc(sizeof(*vc), NULL);
05416 vc->varname = var;
05417 vc->count = 1;
05418 ao2_link(vco, vc);
05419 }
05420
05421 xml_copy_escape(out, var, xml ? 1 | 2 : 0);
05422 if (vc->count > 1) {
05423 ast_str_append(out, 0, "-%d", vc->count);
05424 }
05425 ao2_ref(vc, -1);
05426 ast_str_append(out, 0, xml ? "='" : "</td><td>");
05427 xml_copy_escape(out, val, 0);
05428 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05429 }
05430
05431 if (inobj) {
05432 ast_str_append(out, 0, xml ? " /></response>\n" :
05433 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05434 ao2_ref(vco, -1);
05435 }
05436 }
05437
05438 static int generic_http_callback(struct ast_tcptls_session_instance *ser,
05439 enum ast_http_method method,
05440 enum output_format format,
05441 struct sockaddr_in *remote_address, const char *uri,
05442 struct ast_variable *get_params,
05443 struct ast_variable *headers)
05444 {
05445 struct mansession s = { .session = NULL, .tcptls_session = ser };
05446 struct mansession_session *session = NULL;
05447 uint32_t ident = 0;
05448 int blastaway = 0;
05449 struct ast_variable *v, *cookies, *params = get_params;
05450 char template[] = "/tmp/ast-http-XXXXXX";
05451 struct ast_str *http_header = NULL, *out = NULL;
05452 struct message m = { 0 };
05453 unsigned int x;
05454 size_t hdrlen;
05455
05456 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05457 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05458 return -1;
05459 }
05460
05461 cookies = ast_http_get_cookies(headers);
05462 for (v = cookies; v; v = v->next) {
05463 if (!strcasecmp(v->name, "mansession_id")) {
05464 sscanf(v->value, "%30x", &ident);
05465 break;
05466 }
05467 }
05468 if (cookies) {
05469 ast_variables_destroy(cookies);
05470 }
05471
05472 if (!(session = find_session(ident, 1))) {
05473
05474
05475
05476
05477
05478 if (!(session = build_mansession(*remote_address))) {
05479 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05480 return -1;
05481 }
05482 ao2_lock(session);
05483 session->sin = *remote_address;
05484 session->fd = -1;
05485 session->waiting_thread = AST_PTHREADT_NULL;
05486 session->send_events = 0;
05487 session->inuse = 1;
05488
05489
05490
05491
05492
05493 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
05494 session->last_ev = grab_last();
05495 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05496 }
05497 ao2_unlock(session);
05498
05499 http_header = ast_str_create(128);
05500 out = ast_str_create(2048);
05501
05502 ast_mutex_init(&s.lock);
05503
05504 if (http_header == NULL || out == NULL) {
05505 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05506 goto generic_callback_out;
05507 }
05508
05509 s.session = session;
05510 s.fd = mkstemp(template);
05511 unlink(template);
05512 if (s.fd <= -1) {
05513 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05514 goto generic_callback_out;
05515 }
05516 s.f = fdopen(s.fd, "w+");
05517 if (!s.f) {
05518 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05519 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05520 close(s.fd);
05521 goto generic_callback_out;
05522 }
05523
05524 if (method == AST_HTTP_POST) {
05525 params = ast_http_get_post_vars(ser, headers);
05526 }
05527
05528 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
05529 hdrlen = strlen(v->name) + strlen(v->value) + 3;
05530 m.headers[m.hdrcount] = alloca(hdrlen);
05531 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05532 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05533 m.hdrcount = x + 1;
05534 }
05535
05536 if (process_message(&s, &m)) {
05537 if (session->authenticated) {
05538 if (manager_displayconnects(session)) {
05539 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05540 }
05541 } else {
05542 if (displayconnects) {
05543 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05544 }
05545 }
05546 session->needdestroy = 1;
05547 }
05548
05549 ast_str_append(&http_header, 0,
05550 "Content-type: text/%s\r\n"
05551 "Cache-Control: no-cache;\r\n"
05552 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
05553 "Pragma: SuppressEvents\r\n",
05554 contenttype[format],
05555 session->managerid, httptimeout);
05556
05557 if (format == FORMAT_XML) {
05558 ast_str_append(&out, 0, "<ajax-response>\n");
05559 } else if (format == FORMAT_HTML) {
05560
05561
05562
05563
05564
05565
05566 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
05567 #define TEST_STRING \
05568 "<form action=\"manager\" method=\"post\">\n\
05569 Action: <select name=\"action\">\n\
05570 <option value=\"\">-----></option>\n\
05571 <option value=\"login\">login</option>\n\
05572 <option value=\"command\">Command</option>\n\
05573 <option value=\"waitevent\">waitevent</option>\n\
05574 <option value=\"listcommands\">listcommands</option>\n\
05575 </select>\n\
05576 or <input name=\"action\"><br/>\n\
05577 CLI Command <input name=\"command\"><br>\n\
05578 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
05579 <input type=\"submit\">\n</form>\n"
05580
05581 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>");
05582 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
05583 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
05584 ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
05585 }
05586
05587 if (s.f != NULL) {
05588 char *buf;
05589 size_t l;
05590
05591 if ((l = ftell(s.f))) {
05592 if (MAP_FAILED == (buf = mmap(NULL, l + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) {
05593 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
05594 } else {
05595 buf[l] = '\0';
05596 if (format == FORMAT_XML || format == FORMAT_HTML) {
05597 xml_translate(&out, buf, params, format);
05598 } else {
05599 ast_str_append(&out, 0, "%s", buf);
05600 }
05601 munmap(buf, l + 1);
05602 }
05603 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05604 xml_translate(&out, "", params, format);
05605 }
05606 fclose(s.f);
05607 s.f = NULL;
05608 s.fd = -1;
05609 }
05610
05611 if (format == FORMAT_XML) {
05612 ast_str_append(&out, 0, "</ajax-response>\n");
05613 } else if (format == FORMAT_HTML) {
05614 ast_str_append(&out, 0, "</table></body>\r\n");
05615 }
05616
05617 ao2_lock(session);
05618
05619 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
05620
05621 if (session->needdestroy) {
05622 if (session->inuse == 1) {
05623 ast_debug(1, "Need destroy, doing it now!\n");
05624 blastaway = 1;
05625 } else {
05626 ast_debug(1, "Need destroy, but can't do it yet!\n");
05627 if (session->waiting_thread != AST_PTHREADT_NULL) {
05628 pthread_kill(session->waiting_thread, SIGURG);
05629 }
05630 session->inuse--;
05631 }
05632 } else {
05633 session->inuse--;
05634 }
05635 ao2_unlock(session);
05636
05637 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05638 http_header = out = NULL;
05639
05640 generic_callback_out:
05641 ast_mutex_destroy(&s.lock);
05642
05643
05644
05645 if (method == AST_HTTP_POST && params) {
05646 ast_variables_destroy(params);
05647 }
05648 if (http_header) {
05649 ast_free(http_header);
05650 }
05651 if (out) {
05652 ast_free(out);
05653 }
05654
05655 if (session && blastaway) {
05656 session_destroy(session);
05657 } else if (session && session->f) {
05658 fclose(session->f);
05659 session->f = NULL;
05660 }
05661
05662 return 0;
05663 }
05664
05665 static int auth_http_callback(struct ast_tcptls_session_instance *ser,
05666 enum ast_http_method method,
05667 enum output_format format,
05668 struct sockaddr_in *remote_address, const char *uri,
05669 struct ast_variable *get_params,
05670 struct ast_variable *headers)
05671 {
05672 struct mansession_session *session = NULL;
05673 struct mansession s = { NULL, };
05674 struct ast_variable *v, *params = get_params;
05675 char template[] = "/tmp/ast-http-XXXXXX";
05676 struct ast_str *http_header = NULL, *out = NULL;
05677 size_t result_size = 512;
05678 struct message m = { 0 };
05679 unsigned int x;
05680 size_t hdrlen;
05681
05682 time_t time_now = time(NULL);
05683 unsigned long nonce = 0, nc;
05684 struct ast_http_digest d = { NULL, };
05685 struct ast_manager_user *user = NULL;
05686 int stale = 0;
05687 char resp_hash[256]="";
05688
05689 char u_username[80];
05690 int u_readperm;
05691 int u_writeperm;
05692 int u_writetimeout;
05693 int u_displayconnects;
05694 struct ast_sockaddr addr;
05695
05696 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05697 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05698 return -1;
05699 }
05700
05701
05702 for (v = headers; v; v = v->next) {
05703 if (!strcasecmp(v->name, "Authorization")) {
05704 break;
05705 }
05706 }
05707
05708 if (!v || ast_strlen_zero(v->value)) {
05709 goto out_401;
05710 }
05711
05712
05713 if (ast_string_field_init(&d, 128)) {
05714 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05715 return -1;
05716 }
05717
05718 if (ast_parse_digest(v->value, &d, 0, 1)) {
05719
05720 nonce = 0;
05721 goto out_401;
05722 }
05723 if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
05724 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
05725 nonce = 0;
05726 goto out_401;
05727 }
05728
05729 AST_RWLIST_WRLOCK(&users);
05730 user = get_manager_by_name_locked(d.username);
05731 if(!user) {
05732 AST_RWLIST_UNLOCK(&users);
05733 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05734 nonce = 0;
05735 goto out_401;
05736 }
05737
05738 ast_sockaddr_from_sin(&addr, remote_address);
05739
05740 if (user->ha && !ast_apply_ha(user->ha, &addr)) {
05741 AST_RWLIST_UNLOCK(&users);
05742 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05743 ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
05744 return -1;
05745 }
05746
05747
05748
05749
05750 {
05751 char a2[256];
05752 char a2_hash[256];
05753 char resp[256];
05754
05755
05756 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
05757 ast_md5_hash(a2_hash, a2);
05758
05759 if (d.qop) {
05760
05761 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
05762 } else {
05763
05764 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
05765 }
05766 ast_md5_hash(resp_hash, resp);
05767 }
05768
05769 if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
05770
05771 AST_RWLIST_UNLOCK(&users);
05772 nonce = 0;
05773 goto out_401;
05774 }
05775
05776
05777
05778
05779
05780 ast_copy_string(u_username, user->username, sizeof(u_username));
05781 u_readperm = user->readperm;
05782 u_writeperm = user->writeperm;
05783 u_displayconnects = user->displayconnects;
05784 u_writetimeout = user->writetimeout;
05785 AST_RWLIST_UNLOCK(&users);
05786
05787 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
05788
05789
05790
05791
05792 if (!(session = build_mansession(*remote_address))) {
05793 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05794 return -1;
05795 }
05796 ao2_lock(session);
05797
05798 ast_copy_string(session->username, u_username, sizeof(session->username));
05799 session->managerid = nonce;
05800 session->last_ev = grab_last();
05801 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05802
05803 session->readperm = u_readperm;
05804 session->writeperm = u_writeperm;
05805 session->writetimeout = u_writetimeout;
05806
05807 if (u_displayconnects) {
05808 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05809 }
05810 session->noncetime = session->sessionstart = time_now;
05811 session->authenticated = 1;
05812 } else if (stale) {
05813
05814
05815
05816
05817
05818
05819
05820
05821
05822
05823
05824
05825 nonce = session->managerid;
05826 ao2_unlock(session);
05827 stale = 1;
05828 goto out_401;
05829 } else {
05830 sscanf(d.nc, "%30lx", &nc);
05831 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
05832
05833
05834
05835
05836
05837
05838
05839 session->nc = 0;
05840 session->oldnonce = session->managerid;
05841 nonce = session->managerid = ast_random();
05842 session->noncetime = time_now;
05843 ao2_unlock(session);
05844 stale = 1;
05845 goto out_401;
05846 } else {
05847 session->nc = nc;
05848 }
05849 }
05850
05851
05852
05853 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
05854 ao2_unlock(session);
05855
05856 ast_mutex_init(&s.lock);
05857 s.session = session;
05858 s.fd = mkstemp(template);
05859 unlink(template);
05860 if (s.fd <= -1) {
05861 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05862 goto auth_callback_out;
05863 }
05864 s.f = fdopen(s.fd, "w+");
05865 if (!s.f) {
05866 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05867 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05868 close(s.fd);
05869 goto auth_callback_out;
05870 }
05871
05872 if (method == AST_HTTP_POST) {
05873 params = ast_http_get_post_vars(ser, headers);
05874 }
05875
05876 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
05877 hdrlen = strlen(v->name) + strlen(v->value) + 3;
05878 m.headers[m.hdrcount] = alloca(hdrlen);
05879 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05880 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05881 m.hdrcount = x + 1;
05882 }
05883
05884 if (process_message(&s, &m)) {
05885 if (u_displayconnects) {
05886 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05887 }
05888
05889 session->needdestroy = 1;
05890 }
05891
05892 if (s.f) {
05893 result_size = ftell(s.f);
05894 }
05895
05896 http_header = ast_str_create(80);
05897 out = ast_str_create(result_size * 2 + 512);
05898
05899 if (http_header == NULL || out == NULL) {
05900 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05901 goto auth_callback_out;
05902 }
05903
05904 ast_str_append(&http_header, 0, "Content-type: text/%s", contenttype[format]);
05905
05906 if (format == FORMAT_XML) {
05907 ast_str_append(&out, 0, "<ajax-response>\n");
05908 } else if (format == FORMAT_HTML) {
05909 ast_str_append(&out, 0,
05910 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
05911 "<html><head>\r\n"
05912 "<title>Asterisk™ Manager Interface</title>\r\n"
05913 "</head><body style=\"background-color: #ffffff;\">\r\n"
05914 "<form method=\"POST\">\r\n"
05915 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
05916 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
05917 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
05918 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
05919 }
05920
05921 if (s.f != NULL) {
05922 char *buf;
05923 size_t l = ftell(s.f);
05924
05925 if (l) {
05926 if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
05927 if (format == FORMAT_XML || format == FORMAT_HTML) {
05928 xml_translate(&out, buf, params, format);
05929 } else {
05930 ast_str_append(&out, 0, "%s", buf);
05931 }
05932 munmap(buf, l);
05933 }
05934 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05935 xml_translate(&out, "", params, format);
05936 }
05937 fclose(s.f);
05938 s.f = NULL;
05939 s.fd = -1;
05940 }
05941
05942 if (format == FORMAT_XML) {
05943 ast_str_append(&out, 0, "</ajax-response>\n");
05944 } else if (format == FORMAT_HTML) {
05945 ast_str_append(&out, 0, "</table></form></body></html>\r\n");
05946 }
05947
05948 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05949 http_header = out = NULL;
05950
05951 auth_callback_out:
05952 ast_mutex_destroy(&s.lock);
05953
05954
05955 if (method == AST_HTTP_POST && params) {
05956 ast_variables_destroy(params);
05957 }
05958
05959 ast_free(http_header);
05960 ast_free(out);
05961
05962 ao2_lock(session);
05963 if (session->f) {
05964 fclose(session->f);
05965 }
05966 session->f = NULL;
05967 session->fd = -1;
05968 ao2_unlock(session);
05969
05970 if (session->needdestroy) {
05971 ast_debug(1, "Need destroy, doing it now!\n");
05972 session_destroy(session);
05973 }
05974 ast_string_field_free_memory(&d);
05975 return 0;
05976
05977 out_401:
05978 if (!nonce) {
05979 nonce = ast_random();
05980 }
05981
05982 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
05983 ast_string_field_free_memory(&d);
05984 return 0;
05985 }
05986
05987 static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
05988 {
05989 int retval;
05990 struct sockaddr_in ser_remote_address_tmp;
05991
05992 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05993 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
05994 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05995 return retval;
05996 }
05997
05998 static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
05999 {
06000 int retval;
06001 struct sockaddr_in ser_remote_address_tmp;
06002
06003 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06004 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06005 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06006 return retval;
06007 }
06008
06009 static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
06010 {
06011 int retval;
06012 struct sockaddr_in ser_remote_address_tmp;
06013
06014 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06015 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06016 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06017 return retval;
06018 }
06019
06020 static struct ast_http_uri rawmanuri = {
06021 .description = "Raw HTTP Manager Event Interface",
06022 .uri = "rawman",
06023 .callback = rawman_http_callback,
06024 .data = NULL,
06025 .key = __FILE__,
06026 };
06027
06028 static struct ast_http_uri manageruri = {
06029 .description = "HTML Manager Event Interface",
06030 .uri = "manager",
06031 .callback = manager_http_callback,
06032 .data = NULL,
06033 .key = __FILE__,
06034 };
06035
06036 static struct ast_http_uri managerxmluri = {
06037 .description = "XML Manager Event Interface",
06038 .uri = "mxml",
06039 .callback = mxml_http_callback,
06040 .data = NULL,
06041 .key = __FILE__,
06042 };
06043
06044
06045
06046 static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
06047 {
06048 int retval;
06049 struct sockaddr_in ser_remote_address_tmp;
06050
06051 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06052 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06053 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06054 return retval;
06055 }
06056
06057 static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
06058 {
06059 int retval;
06060 struct sockaddr_in ser_remote_address_tmp;
06061
06062 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06063 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06064 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06065 return retval;
06066 }
06067
06068 static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
06069 {
06070 int retval;
06071 struct sockaddr_in ser_remote_address_tmp;
06072
06073 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06074 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06075 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06076 return retval;
06077 }
06078
06079 static struct ast_http_uri arawmanuri = {
06080 .description = "Raw HTTP Manager Event Interface w/Digest authentication",
06081 .uri = "arawman",
06082 .has_subtree = 0,
06083 .callback = auth_rawman_http_callback,
06084 .data = NULL,
06085 .key = __FILE__,
06086 };
06087
06088 static struct ast_http_uri amanageruri = {
06089 .description = "HTML Manager Event Interface w/Digest authentication",
06090 .uri = "amanager",
06091 .has_subtree = 0,
06092 .callback = auth_manager_http_callback,
06093 .data = NULL,
06094 .key = __FILE__,
06095 };
06096
06097 static struct ast_http_uri amanagerxmluri = {
06098 .description = "XML Manager Event Interface w/Digest authentication",
06099 .uri = "amxml",
06100 .has_subtree = 0,
06101 .callback = auth_mxml_http_callback,
06102 .data = NULL,
06103 .key = __FILE__,
06104 };
06105
06106 static int registered = 0;
06107 static int webregged = 0;
06108
06109
06110
06111
06112 static void purge_old_stuff(void *data)
06113 {
06114 purge_sessions(1);
06115 purge_events();
06116 }
06117
06118 static struct ast_tls_config ami_tls_cfg;
06119 static struct ast_tcptls_session_args ami_desc = {
06120 .accept_fd = -1,
06121 .master = AST_PTHREADT_NULL,
06122 .tls_cfg = NULL,
06123 .poll_timeout = 5000,
06124 .periodic_fn = purge_old_stuff,
06125 .name = "AMI server",
06126 .accept_fn = ast_tcptls_server_root,
06127 .worker_fn = session_do,
06128 };
06129
06130 static struct ast_tcptls_session_args amis_desc = {
06131 .accept_fd = -1,
06132 .master = AST_PTHREADT_NULL,
06133 .tls_cfg = &ami_tls_cfg,
06134 .poll_timeout = -1,
06135 .name = "AMI TLS server",
06136 .accept_fn = ast_tcptls_server_root,
06137 .worker_fn = session_do,
06138 };
06139
06140
06141 static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06142 {
06143 switch (cmd) {
06144 case CLI_INIT:
06145 e->command = "manager show settings";
06146 e->usage =
06147 "Usage: manager show settings\n"
06148 " Provides detailed list of the configuration of the Manager.\n";
06149 return NULL;
06150 case CLI_GENERATE:
06151 return NULL;
06152 }
06153 #define FORMAT " %-25.25s %-15.15s\n"
06154 #define FORMAT2 " %-25.25s %-15d\n"
06155 if (a->argc != 3) {
06156 return CLI_SHOWUSAGE;
06157 }
06158 ast_cli(a->fd, "\nGlobal Settings:\n");
06159 ast_cli(a->fd, "----------------\n");
06160 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06161 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06162 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06163 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06164 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06165 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06166 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06167 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06168 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06169 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06170 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06171 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06172 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06173 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06174 ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06175 #undef FORMAT
06176 #undef FORMAT2
06177
06178 return CLI_SUCCESS;
06179 }
06180
06181 static struct ast_cli_entry cli_manager[] = {
06182 AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
06183 AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
06184 AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
06185 AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
06186 AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
06187 AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
06188 AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
06189 AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
06190 AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
06191 };
06192
06193 static int __init_manager(int reload)
06194 {
06195 struct ast_config *ucfg = NULL, *cfg = NULL;
06196 const char *val;
06197 char *cat = NULL;
06198 int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06199 struct ast_manager_user *user = NULL;
06200 struct ast_variable *var;
06201 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06202 char a1[256];
06203 char a1_hash[256];
06204 struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06205 struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06206
06207 if (!registered) {
06208
06209 ast_manager_register_xml("Ping", 0, action_ping);
06210 ast_manager_register_xml("Events", 0, action_events);
06211 ast_manager_register_xml("Logoff", 0, action_logoff);
06212 ast_manager_register_xml("Login", 0, action_login);
06213 ast_manager_register_xml("Challenge", 0, action_challenge);
06214 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06215 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06216 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06217 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06218 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06219 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06220 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06221 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06222 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06223 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06224 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06225 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06226 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06227 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06228 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06229 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06230 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06231 ast_manager_register_xml("ListCommands", 0, action_listcommands);
06232 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06233 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06234 ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06235 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06236 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06237 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06238 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06239 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06240 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06241 ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06242
06243 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06244 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06245 registered = 1;
06246
06247 append_event("Event: Placeholder\r\n\r\n", 0);
06248 }
06249 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
06250 return 0;
06251 }
06252
06253 manager_enabled = DEFAULT_ENABLED;
06254 webmanager_enabled = DEFAULT_WEBENABLED;
06255 displayconnects = DEFAULT_DISPLAYCONNECTS;
06256 broken_events_action = DEFAULT_BROKENEVENTSACTION;
06257 block_sockets = DEFAULT_BLOCKSOCKETS;
06258 timestampevents = DEFAULT_TIMESTAMPEVENTS;
06259 httptimeout = DEFAULT_HTTPTIMEOUT;
06260 authtimeout = DEFAULT_AUTHTIMEOUT;
06261 authlimit = DEFAULT_AUTHLIMIT;
06262
06263 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06264 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
06265 return 0;
06266 }
06267
06268
06269 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
06270 memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
06271 memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
06272 amis_desc_local_address_tmp.sin_port = htons(5039);
06273 ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06274
06275 ami_tls_cfg.enabled = 0;
06276 if (ami_tls_cfg.certfile) {
06277 ast_free(ami_tls_cfg.certfile);
06278 }
06279 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
06280 if (ami_tls_cfg.pvtfile) {
06281 ast_free(ami_tls_cfg.pvtfile);
06282 }
06283 ami_tls_cfg.pvtfile = ast_strdup("");
06284 if (ami_tls_cfg.cipher) {
06285 ast_free(ami_tls_cfg.cipher);
06286 }
06287 ami_tls_cfg.cipher = ast_strdup("");
06288
06289 free_channelvars();
06290
06291 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06292 val = var->value;
06293
06294 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06295 continue;
06296 }
06297
06298 if (!strcasecmp(var->name, "enabled")) {
06299 manager_enabled = ast_true(val);
06300 } else if (!strcasecmp(var->name, "block-sockets")) {
06301 block_sockets = ast_true(val);
06302 } else if (!strcasecmp(var->name, "webenabled")) {
06303 webmanager_enabled = ast_true(val);
06304 } else if (!strcasecmp(var->name, "port")) {
06305 ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06306 } else if (!strcasecmp(var->name, "bindaddr")) {
06307 if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06308 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06309 memset(&ami_desc_local_address_tmp.sin_addr, 0,
06310 sizeof(ami_desc_local_address_tmp.sin_addr));
06311 }
06312 } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06313 broken_events_action = ast_true(val);
06314 } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06315 allowmultiplelogin = ast_true(val);
06316 } else if (!strcasecmp(var->name, "displayconnects")) {
06317 displayconnects = ast_true(val);
06318 } else if (!strcasecmp(var->name, "timestampevents")) {
06319 timestampevents = ast_true(val);
06320 } else if (!strcasecmp(var->name, "debug")) {
06321 manager_debug = ast_true(val);
06322 } else if (!strcasecmp(var->name, "httptimeout")) {
06323 newhttptimeout = atoi(val);
06324 } else if (!strcasecmp(var->name, "authtimeout")) {
06325 int timeout = atoi(var->value);
06326
06327 if (timeout < 1) {
06328 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06329 } else {
06330 authtimeout = timeout;
06331 }
06332 } else if (!strcasecmp(var->name, "authlimit")) {
06333 int limit = atoi(var->value);
06334
06335 if (limit < 1) {
06336 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06337 } else {
06338 authlimit = limit;
06339 }
06340 } else if (!strcasecmp(var->name, "channelvars")) {
06341 struct manager_channel_variable *mcv;
06342 char *remaining = ast_strdupa(val), *next;
06343 ast_free(manager_channelvars);
06344 manager_channelvars = ast_strdup(val);
06345 AST_RWLIST_WRLOCK(&channelvars);
06346 while ((next = strsep(&remaining, ",|"))) {
06347 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06348 break;
06349 }
06350 strcpy(mcv->name, next);
06351 if (strchr(next, '(')) {
06352 mcv->isfunc = 1;
06353 }
06354 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06355 }
06356 AST_RWLIST_UNLOCK(&channelvars);
06357 } else {
06358 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06359 var->name, val);
06360 }
06361 }
06362
06363 ami_desc_local_address_tmp.sin_family = AF_INET;
06364 amis_desc_local_address_tmp.sin_family = AF_INET;
06365
06366
06367 if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06368 amis_desc_local_address_tmp.sin_addr =
06369 ami_desc_local_address_tmp.sin_addr;
06370 }
06371
06372 if (manager_enabled) {
06373 ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
06374 ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06375 }
06376
06377 AST_RWLIST_WRLOCK(&users);
06378
06379
06380 ucfg = ast_config_load2("users.conf", "manager", config_flags);
06381 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
06382 const char *hasmanager;
06383 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
06384
06385 while ((cat = ast_category_browse(ucfg, cat))) {
06386 if (!strcasecmp(cat, "general")) {
06387 continue;
06388 }
06389
06390 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
06391 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
06392 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
06393 const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
06394 const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
06395 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
06396 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
06397
06398
06399
06400
06401 if (!(user = get_manager_by_name_locked(cat))) {
06402 if (!(user = ast_calloc(1, sizeof(*user)))) {
06403 break;
06404 }
06405
06406
06407 ast_copy_string(user->username, cat, sizeof(user->username));
06408
06409 AST_LIST_INSERT_TAIL(&users, user, list);
06410 user->ha = NULL;
06411 user->keep = 1;
06412 user->readperm = -1;
06413 user->writeperm = -1;
06414
06415 user->displayconnects = displayconnects;
06416 user->writetimeout = 100;
06417 }
06418
06419 if (!user_secret) {
06420 user_secret = ast_variable_retrieve(ucfg, "general", "secret");
06421 }
06422 if (!user_read) {
06423 user_read = ast_variable_retrieve(ucfg, "general", "read");
06424 }
06425 if (!user_write) {
06426 user_write = ast_variable_retrieve(ucfg, "general", "write");
06427 }
06428 if (!user_displayconnects) {
06429 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
06430 }
06431 if (!user_writetimeout) {
06432 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
06433 }
06434
06435 if (!ast_strlen_zero(user_secret)) {
06436 if (user->secret) {
06437 ast_free(user->secret);
06438 }
06439 user->secret = ast_strdup(user_secret);
06440 }
06441
06442 if (user_read) {
06443 user->readperm = get_perm(user_read);
06444 }
06445 if (user_write) {
06446 user->writeperm = get_perm(user_write);
06447 }
06448 if (user_displayconnects) {
06449 user->displayconnects = ast_true(user_displayconnects);
06450 }
06451 if (user_writetimeout) {
06452 int value = atoi(user_writetimeout);
06453 if (value < 100) {
06454 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
06455 } else {
06456 user->writetimeout = value;
06457 }
06458 }
06459 }
06460 }
06461 ast_config_destroy(ucfg);
06462 }
06463
06464
06465
06466 while ((cat = ast_category_browse(cfg, cat))) {
06467 struct ast_ha *oldha;
06468
06469 if (!strcasecmp(cat, "general")) {
06470 continue;
06471 }
06472
06473
06474 if (!(user = get_manager_by_name_locked(cat))) {
06475 if (!(user = ast_calloc(1, sizeof(*user)))) {
06476 break;
06477 }
06478
06479 ast_copy_string(user->username, cat, sizeof(user->username));
06480
06481 user->ha = NULL;
06482 user->readperm = 0;
06483 user->writeperm = 0;
06484
06485 user->displayconnects = displayconnects;
06486 user->writetimeout = 100;
06487 user->whitefilters = ao2_container_alloc(1, NULL, NULL);
06488 user->blackfilters = ao2_container_alloc(1, NULL, NULL);
06489
06490
06491 AST_RWLIST_INSERT_TAIL(&users, user, list);
06492 } else {
06493 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06494 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06495 }
06496
06497
06498 user->keep = 1;
06499 oldha = user->ha;
06500 user->ha = NULL;
06501
06502 var = ast_variable_browse(cfg, cat);
06503 for (; var; var = var->next) {
06504 if (!strcasecmp(var->name, "secret")) {
06505 if (user->secret) {
06506 ast_free(user->secret);
06507 }
06508 user->secret = ast_strdup(var->value);
06509 } else if (!strcasecmp(var->name, "deny") ||
06510 !strcasecmp(var->name, "permit")) {
06511 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
06512 } else if (!strcasecmp(var->name, "read") ) {
06513 user->readperm = get_perm(var->value);
06514 } else if (!strcasecmp(var->name, "write") ) {
06515 user->writeperm = get_perm(var->value);
06516 } else if (!strcasecmp(var->name, "displayconnects") ) {
06517 user->displayconnects = ast_true(var->value);
06518 } else if (!strcasecmp(var->name, "writetimeout")) {
06519 int value = atoi(var->value);
06520 if (value < 100) {
06521 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
06522 } else {
06523 user->writetimeout = value;
06524 }
06525 } else if (!strcasecmp(var->name, "eventfilter")) {
06526 const char *value = var->value;
06527 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
06528 if (new_filter) {
06529 int is_blackfilter;
06530 if (value[0] == '!') {
06531 is_blackfilter = 1;
06532 value++;
06533 } else {
06534 is_blackfilter = 0;
06535 }
06536 if (regcomp(new_filter, value, 0)) {
06537 ao2_t_ref(new_filter, -1, "failed to make regx");
06538 } else {
06539 if (is_blackfilter) {
06540 ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
06541 } else {
06542 ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
06543 }
06544 }
06545 }
06546 } else {
06547 ast_debug(1, "%s is an unknown option.\n", var->name);
06548 }
06549 }
06550 ast_free_ha(oldha);
06551 }
06552 ast_config_destroy(cfg);
06553
06554
06555 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
06556 if (user->keep) {
06557 user->keep = 0;
06558
06559
06560 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
06561 ast_md5_hash(a1_hash,a1);
06562 if (user->a1_hash) {
06563 ast_free(user->a1_hash);
06564 }
06565 user->a1_hash = ast_strdup(a1_hash);
06566 continue;
06567 }
06568
06569 AST_RWLIST_REMOVE_CURRENT(list);
06570 ast_debug(4, "Pruning user '%s'\n", user->username);
06571
06572 if (user->a1_hash) {
06573 ast_free(user->a1_hash);
06574 }
06575 if (user->secret) {
06576 ast_free(user->secret);
06577 }
06578 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06579 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06580 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06581 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06582 ast_free_ha(user->ha);
06583 ast_free(user);
06584 }
06585 AST_RWLIST_TRAVERSE_SAFE_END;
06586
06587 AST_RWLIST_UNLOCK(&users);
06588
06589 if (!reload) {
06590
06591 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06592 }
06593
06594 if (webmanager_enabled && manager_enabled) {
06595 if (!webregged) {
06596
06597 ast_http_uri_link(&rawmanuri);
06598 ast_http_uri_link(&manageruri);
06599 ast_http_uri_link(&managerxmluri);
06600
06601 ast_http_uri_link(&arawmanuri);
06602 ast_http_uri_link(&amanageruri);
06603 ast_http_uri_link(&amanagerxmluri);
06604 webregged = 1;
06605 }
06606 } else {
06607 if (webregged) {
06608 ast_http_uri_unlink(&rawmanuri);
06609 ast_http_uri_unlink(&manageruri);
06610 ast_http_uri_unlink(&managerxmluri);
06611
06612 ast_http_uri_unlink(&arawmanuri);
06613 ast_http_uri_unlink(&amanageruri);
06614 ast_http_uri_unlink(&amanagerxmluri);
06615 webregged = 0;
06616 }
06617 }
06618
06619 if (newhttptimeout > 0) {
06620 httptimeout = newhttptimeout;
06621 }
06622
06623 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
06624
06625 ast_tcptls_server_start(&ami_desc);
06626 if (ast_ssl_setup(amis_desc.tls_cfg)) {
06627 ast_tcptls_server_start(&amis_desc);
06628 }
06629 return 0;
06630 }
06631
06632
06633 static void free_channelvars(void)
06634 {
06635 struct manager_channel_variable *var;
06636 AST_RWLIST_WRLOCK(&channelvars);
06637 while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
06638 ast_free(var);
06639 }
06640 AST_RWLIST_UNLOCK(&channelvars);
06641 }
06642
06643 int init_manager(void)
06644 {
06645 return __init_manager(0);
06646 }
06647
06648 int reload_manager(void)
06649 {
06650 return __init_manager(1);
06651 }
06652
06653 int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
06654 {
06655 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
06656
06657 return 0;
06658 }
06659
06660 int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
06661 {
06662 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
06663 }
06664
06665 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
06666 {
06667 struct ast_datastore *datastore = NULL;
06668
06669 if (info == NULL)
06670 return NULL;
06671
06672 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
06673 if (datastore->info != info) {
06674 continue;
06675 }
06676
06677 if (uid == NULL) {
06678
06679 break;
06680 }
06681
06682 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
06683
06684 break;
06685 }
06686 }
06687 AST_LIST_TRAVERSE_SAFE_END;
06688
06689 return datastore;
06690 }