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