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
00045
00046
00047
00048 #include "asterisk.h"
00049
00050 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416067 $")
00051
00052 #include "asterisk/_private.h"
00053 #include "asterisk/paths.h"
00054 #include <ctype.h>
00055 #include <sys/time.h>
00056 #include <signal.h>
00057 #include <sys/mman.h>
00058 #include <sys/types.h>
00059 #include <regex.h>
00060
00061 #include "asterisk/channel.h"
00062 #include "asterisk/file.h"
00063 #include "asterisk/manager.h"
00064 #include "asterisk/module.h"
00065 #include "asterisk/config.h"
00066 #include "asterisk/callerid.h"
00067 #include "asterisk/lock.h"
00068 #include "asterisk/cli.h"
00069 #include "asterisk/app.h"
00070 #include "asterisk/pbx.h"
00071 #include "asterisk/md5.h"
00072 #include "asterisk/acl.h"
00073 #include "asterisk/utils.h"
00074 #include "asterisk/tcptls.h"
00075 #include "asterisk/http.h"
00076 #include "asterisk/ast_version.h"
00077 #include "asterisk/threadstorage.h"
00078 #include "asterisk/linkedlists.h"
00079 #include "asterisk/term.h"
00080 #include "asterisk/astobj2.h"
00081 #include "asterisk/features.h"
00082 #include "asterisk/security_events.h"
00083 #include "asterisk/event.h"
00084 #include "asterisk/aoc.h"
00085 #include "asterisk/stringfields.h"
00086 #include "asterisk/presencestate.h"
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
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
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
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 enum error_type {
00963 UNKNOWN_ACTION = 1,
00964 UNKNOWN_CATEGORY,
00965 UNSPECIFIED_CATEGORY,
00966 UNSPECIFIED_ARGUMENT,
00967 FAILURE_ALLOCATION,
00968 FAILURE_NEWCAT,
00969 FAILURE_DELCAT,
00970 FAILURE_EMPTYCAT,
00971 FAILURE_UPDATE,
00972 FAILURE_DELETE,
00973 FAILURE_APPEND
00974 };
00975
00976 enum add_filter_result {
00977 FILTER_SUCCESS,
00978 FILTER_ALLOC_FAILED,
00979 FILTER_COMPILE_FAIL,
00980 };
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001 struct eventqent {
01002 int usecount;
01003 int category;
01004 unsigned int seq;
01005 struct timeval tv;
01006 AST_RWLIST_ENTRY(eventqent) eq_next;
01007 char eventdata[1];
01008 };
01009
01010 static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
01011
01012 static int displayconnects = 1;
01013 static int allowmultiplelogin = 1;
01014 static int timestampevents;
01015 static int httptimeout = 60;
01016 static int broken_events_action = 0;
01017 static int manager_enabled = 0;
01018 static int webmanager_enabled = 0;
01019 static int manager_debug = 0;
01020 static int authtimeout;
01021 static int authlimit;
01022 static char *manager_channelvars;
01023
01024 #define DEFAULT_REALM "asterisk"
01025 static char global_realm[MAXHOSTNAMELEN];
01026
01027 static int unauth_sessions = 0;
01028 static struct ast_event_sub *acl_change_event_subscription;
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 #define MAX_BLACKLIST_CMD_LEN 2
01041 static const struct {
01042 const char *words[AST_MAX_CMD_LEN];
01043 } command_blacklist[] = {
01044 {{ "module", "load", NULL }},
01045 {{ "module", "unload", NULL }},
01046 {{ "restart", "gracefully", NULL }},
01047 };
01048
01049 static void acl_change_event_cb(const struct ast_event *event, void *userdata);
01050
01051 static void acl_change_event_subscribe(void)
01052 {
01053 if (!acl_change_event_subscription) {
01054 acl_change_event_subscription = ast_event_subscribe(AST_EVENT_ACL_CHANGE,
01055 acl_change_event_cb, "Manager must react to Named ACL changes", NULL, AST_EVENT_IE_END);
01056 }
01057 }
01058
01059 static void acl_change_event_unsubscribe(void)
01060 {
01061 if (acl_change_event_subscription) {
01062 acl_change_event_subscription = ast_event_unsubscribe(acl_change_event_subscription);
01063 }
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098 struct mansession_session {
01099
01100 struct ast_sockaddr addr;
01101 FILE *f;
01102 int fd;
01103 int inuse;
01104 int needdestroy;
01105 pthread_t waiting_thread;
01106 uint32_t managerid;
01107 time_t sessionstart;
01108 struct timeval sessionstart_tv;
01109 time_t sessiontimeout;
01110 char username[80];
01111 char challenge[10];
01112 int authenticated;
01113 int readperm;
01114 int writeperm;
01115 char inbuf[1025];
01116 int inlen;
01117 struct ao2_container *whitefilters;
01118 struct ao2_container *blackfilters;
01119 struct ast_variable *chanvars;
01120 int send_events;
01121 struct eventqent *last_ev;
01122 int writetimeout;
01123 time_t authstart;
01124 int pending_event;
01125 time_t noncetime;
01126 unsigned long oldnonce;
01127 unsigned long nc;
01128 AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores;
01129 AST_LIST_ENTRY(mansession_session) list;
01130 };
01131
01132 enum mansession_message_parsing {
01133 MESSAGE_OKAY,
01134 MESSAGE_LINE_TOO_LONG
01135 };
01136
01137
01138
01139
01140
01141
01142 struct mansession {
01143 struct mansession_session *session;
01144 struct ast_tcptls_session_instance *tcptls_session;
01145 FILE *f;
01146 int fd;
01147 enum mansession_message_parsing parsing;
01148 int write_error:1;
01149 struct manager_custom_hook *hook;
01150 ast_mutex_t lock;
01151 };
01152
01153
01154 static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
01155
01156 struct manager_channel_variable {
01157 AST_LIST_ENTRY(manager_channel_variable) entry;
01158 unsigned int isfunc:1;
01159 char name[0];
01160 };
01161
01162 static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
01163
01164
01165
01166
01167
01168
01169
01170 struct ast_manager_user {
01171 char username[80];
01172 char *secret;
01173 int readperm;
01174 int writeperm;
01175 int writetimeout;
01176 int displayconnects;
01177 int keep;
01178 struct ao2_container *whitefilters;
01179 struct ao2_container *blackfilters;
01180 struct ast_acl_list *acl;
01181 char *a1_hash;
01182 struct ast_variable *chanvars;
01183 AST_RWLIST_ENTRY(ast_manager_user) list;
01184 };
01185
01186
01187 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
01188
01189
01190 static AST_RWLIST_HEAD_STATIC(actions, manager_action);
01191
01192
01193 static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
01194
01195
01196 static AO2_GLOBAL_OBJ_STATIC(event_docs);
01197
01198 static void free_channelvars(void);
01199
01200 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210 static struct manager_action *action_find(const char *name)
01211 {
01212 struct manager_action *act;
01213
01214 AST_RWLIST_RDLOCK(&actions);
01215 AST_RWLIST_TRAVERSE(&actions, act, list) {
01216 if (!strcasecmp(name, act->action)) {
01217 ao2_t_ref(act, +1, "found action object");
01218 break;
01219 }
01220 }
01221 AST_RWLIST_UNLOCK(&actions);
01222
01223 return act;
01224 }
01225
01226
01227 void ast_manager_register_hook(struct manager_custom_hook *hook)
01228 {
01229 AST_RWLIST_WRLOCK(&manager_hooks);
01230 AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
01231 AST_RWLIST_UNLOCK(&manager_hooks);
01232 }
01233
01234
01235 void ast_manager_unregister_hook(struct manager_custom_hook *hook)
01236 {
01237 AST_RWLIST_WRLOCK(&manager_hooks);
01238 AST_RWLIST_REMOVE(&manager_hooks, hook, list);
01239 AST_RWLIST_UNLOCK(&manager_hooks);
01240 }
01241
01242 int check_manager_enabled(void)
01243 {
01244 return manager_enabled;
01245 }
01246
01247 int check_webmanager_enabled(void)
01248 {
01249 return (webmanager_enabled && manager_enabled);
01250 }
01251
01252
01253
01254
01255
01256 static struct eventqent *grab_last(void)
01257 {
01258 struct eventqent *ret;
01259
01260 AST_RWLIST_WRLOCK(&all_events);
01261 ret = AST_RWLIST_LAST(&all_events);
01262
01263
01264
01265 if (ret) {
01266 ast_atomic_fetchadd_int(&ret->usecount, 1);
01267 }
01268 AST_RWLIST_UNLOCK(&all_events);
01269 return ret;
01270 }
01271
01272
01273
01274
01275
01276 static void purge_events(void)
01277 {
01278 struct eventqent *ev;
01279 struct timeval now = ast_tvnow();
01280
01281 AST_RWLIST_WRLOCK(&all_events);
01282 while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
01283 ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
01284 AST_RWLIST_REMOVE_HEAD(&all_events, eq_next);
01285 ast_free(ev);
01286 }
01287
01288 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next) {
01289
01290 if (!AST_RWLIST_NEXT(ev, eq_next)) {
01291 break;
01292 }
01293
01294
01295 if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
01296 AST_RWLIST_REMOVE_CURRENT(eq_next);
01297 ast_free(ev);
01298 }
01299 }
01300 AST_RWLIST_TRAVERSE_SAFE_END;
01301 AST_RWLIST_UNLOCK(&all_events);
01302 }
01303
01304
01305
01306
01307
01308 static const struct permalias {
01309 int num;
01310 const char *label;
01311 } perms[] = {
01312 { EVENT_FLAG_SYSTEM, "system" },
01313 { EVENT_FLAG_CALL, "call" },
01314 { EVENT_FLAG_LOG, "log" },
01315 { EVENT_FLAG_VERBOSE, "verbose" },
01316 { EVENT_FLAG_COMMAND, "command" },
01317 { EVENT_FLAG_AGENT, "agent" },
01318 { EVENT_FLAG_USER, "user" },
01319 { EVENT_FLAG_CONFIG, "config" },
01320 { EVENT_FLAG_DTMF, "dtmf" },
01321 { EVENT_FLAG_REPORTING, "reporting" },
01322 { EVENT_FLAG_CDR, "cdr" },
01323 { EVENT_FLAG_DIALPLAN, "dialplan" },
01324 { EVENT_FLAG_ORIGINATE, "originate" },
01325 { EVENT_FLAG_AGI, "agi" },
01326 { EVENT_FLAG_CC, "cc" },
01327 { EVENT_FLAG_AOC, "aoc" },
01328 { EVENT_FLAG_TEST, "test" },
01329 { EVENT_FLAG_MESSAGE, "message" },
01330 { INT_MAX, "all" },
01331 { 0, "none" },
01332 };
01333
01334
01335 static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
01336 {
01337 if (!(writepermlist & EVENT_FLAG_SYSTEM)
01338 && (
01339 strstr(evaluating, "SHELL") ||
01340 strstr(evaluating, "EVAL")
01341 )) {
01342 return 0;
01343 }
01344 return 1;
01345 }
01346
01347
01348
01349 static const char *user_authority_to_str(int authority, struct ast_str **res)
01350 {
01351 int i;
01352 char *sep = "";
01353
01354 ast_str_reset(*res);
01355 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
01356 if ((authority & perms[i].num) == perms[i].num) {
01357 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
01358 sep = ",";
01359 }
01360 }
01361
01362 if (ast_str_strlen(*res) == 0)
01363 ast_str_append(res, 0, "<none>");
01364
01365 return ast_str_buffer(*res);
01366 }
01367
01368
01369
01370
01371 static const char *authority_to_str(int authority, struct ast_str **res)
01372 {
01373 int i;
01374 char *sep = "";
01375
01376 ast_str_reset(*res);
01377 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
01378 if (authority & perms[i].num) {
01379 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
01380 sep = ",";
01381 }
01382 }
01383
01384 if (ast_str_strlen(*res) == 0)
01385 ast_str_append(res, 0, "<none>");
01386
01387 return ast_str_buffer(*res);
01388 }
01389
01390
01391
01392
01393
01394
01395 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
01396 {
01397 const char *val = bigstr, *next;
01398
01399 do {
01400 if ((next = strchr(val, delim))) {
01401 if (!strncmp(val, smallstr, (next - val))) {
01402 return 1;
01403 } else {
01404 continue;
01405 }
01406 } else {
01407 return !strcmp(smallstr, val);
01408 }
01409 } while (*(val = (next + 1)));
01410
01411 return 0;
01412 }
01413
01414 static int get_perm(const char *instr)
01415 {
01416 int x = 0, ret = 0;
01417
01418 if (!instr) {
01419 return 0;
01420 }
01421
01422 for (x = 0; x < ARRAY_LEN(perms); x++) {
01423 if (ast_instring(instr, perms[x].label, ',')) {
01424 ret |= perms[x].num;
01425 }
01426 }
01427
01428 return ret;
01429 }
01430
01431
01432
01433
01434
01435 static int strings_to_mask(const char *string)
01436 {
01437 const char *p;
01438
01439 if (ast_strlen_zero(string)) {
01440 return -1;
01441 }
01442
01443 for (p = string; *p; p++) {
01444 if (*p < '0' || *p > '9') {
01445 break;
01446 }
01447 }
01448 if (!*p) {
01449 return atoi(string);
01450 }
01451 if (ast_false(string)) {
01452 return 0;
01453 }
01454 if (ast_true(string)) {
01455 int x, ret = 0;
01456 for (x = 0; x < ARRAY_LEN(perms); x++) {
01457 ret |= perms[x].num;
01458 }
01459 return ret;
01460 }
01461 return get_perm(string);
01462 }
01463
01464
01465
01466 static struct mansession_session *unref_mansession(struct mansession_session *s)
01467 {
01468 int refcount = ao2_ref(s, -1);
01469 if (manager_debug) {
01470 ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1);
01471 }
01472 return NULL;
01473 }
01474
01475 static void event_filter_destructor(void *obj)
01476 {
01477 regex_t *regex_filter = obj;
01478 regfree(regex_filter);
01479 }
01480
01481 static void session_destructor(void *obj)
01482 {
01483 struct mansession_session *session = obj;
01484 struct eventqent *eqe = session->last_ev;
01485 struct ast_datastore *datastore;
01486
01487
01488 while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
01489
01490 ast_datastore_free(datastore);
01491 }
01492
01493 if (session->f != NULL) {
01494 fflush(session->f);
01495 fclose(session->f);
01496 }
01497 if (eqe) {
01498 ast_atomic_fetchadd_int(&eqe->usecount, -1);
01499 }
01500 if (session->chanvars) {
01501 ast_variables_destroy(session->chanvars);
01502 }
01503
01504 if (session->whitefilters) {
01505 ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
01506 }
01507
01508 if (session->blackfilters) {
01509 ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
01510 }
01511 }
01512
01513
01514 static struct mansession_session *build_mansession(const struct ast_sockaddr *addr)
01515 {
01516 struct ao2_container *sessions;
01517 struct mansession_session *newsession;
01518
01519 newsession = ao2_alloc(sizeof(*newsession), session_destructor);
01520 if (!newsession) {
01521 return NULL;
01522 }
01523
01524 newsession->whitefilters = ao2_container_alloc(1, NULL, NULL);
01525 newsession->blackfilters = ao2_container_alloc(1, NULL, NULL);
01526 if (!newsession->whitefilters || !newsession->blackfilters) {
01527 ao2_ref(newsession, -1);
01528 return NULL;
01529 }
01530
01531 newsession->fd = -1;
01532 newsession->waiting_thread = AST_PTHREADT_NULL;
01533 newsession->writetimeout = 100;
01534 newsession->send_events = -1;
01535 ast_sockaddr_copy(&newsession->addr, addr);
01536
01537 sessions = ao2_global_obj_ref(mgr_sessions);
01538 if (sessions) {
01539 ao2_link(sessions, newsession);
01540 ao2_ref(sessions, -1);
01541 }
01542
01543 return newsession;
01544 }
01545
01546 static int mansession_cmp_fn(void *obj, void *arg, int flags)
01547 {
01548 struct mansession_session *s = obj;
01549 char *str = arg;
01550 return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
01551 }
01552
01553 static void session_destroy(struct mansession_session *s)
01554 {
01555 struct ao2_container *sessions;
01556
01557 sessions = ao2_global_obj_ref(mgr_sessions);
01558 if (sessions) {
01559 ao2_unlink(sessions, s);
01560 ao2_ref(sessions, -1);
01561 }
01562 unref_mansession(s);
01563 }
01564
01565
01566 static int check_manager_session_inuse(const char *name)
01567 {
01568 struct ao2_container *sessions;
01569 struct mansession_session *session;
01570 int inuse = 0;
01571
01572 sessions = ao2_global_obj_ref(mgr_sessions);
01573 if (sessions) {
01574 session = ao2_find(sessions, (char *) name, 0);
01575 ao2_ref(sessions, -1);
01576 if (session) {
01577 unref_mansession(session);
01578 inuse = 1;
01579 }
01580 }
01581 return inuse;
01582 }
01583
01584
01585
01586
01587
01588
01589 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
01590 {
01591 struct ast_manager_user *user = NULL;
01592
01593 AST_RWLIST_TRAVERSE(&users, user, list) {
01594 if (!strcasecmp(user->username, name)) {
01595 break;
01596 }
01597 }
01598
01599 return user;
01600 }
01601
01602
01603
01604
01605
01606 static int manager_displayconnects(struct mansession_session *session)
01607 {
01608 struct ast_manager_user *user = NULL;
01609 int ret = 0;
01610
01611 AST_RWLIST_RDLOCK(&users);
01612 if ((user = get_manager_by_name_locked(session->username))) {
01613 ret = user->displayconnects;
01614 }
01615 AST_RWLIST_UNLOCK(&users);
01616
01617 return ret;
01618 }
01619
01620 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01621 {
01622 struct manager_action *cur;
01623 struct ast_str *authority;
01624 int num, l, which;
01625 char *ret = NULL;
01626 #ifdef AST_XML_DOCS
01627 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
01628 #endif
01629
01630 switch (cmd) {
01631 case CLI_INIT:
01632 e->command = "manager show command";
01633 e->usage =
01634 "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
01635 " Shows the detailed description for a specific Asterisk manager interface command.\n";
01636 return NULL;
01637 case CLI_GENERATE:
01638 l = strlen(a->word);
01639 which = 0;
01640 AST_RWLIST_RDLOCK(&actions);
01641 AST_RWLIST_TRAVERSE(&actions, cur, list) {
01642 if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
01643 ret = ast_strdup(cur->action);
01644 break;
01645 }
01646 }
01647 AST_RWLIST_UNLOCK(&actions);
01648 return ret;
01649 }
01650 authority = ast_str_alloca(80);
01651 if (a->argc < 4) {
01652 return CLI_SHOWUSAGE;
01653 }
01654
01655 #ifdef AST_XML_DOCS
01656
01657 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01658 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
01659 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01660 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
01661 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
01662 #endif
01663
01664 AST_RWLIST_RDLOCK(&actions);
01665 AST_RWLIST_TRAVERSE(&actions, cur, list) {
01666 for (num = 3; num < a->argc; num++) {
01667 if (!strcasecmp(cur->action, a->argv[num])) {
01668 #ifdef AST_XML_DOCS
01669 if (cur->docsrc == AST_XML_DOC) {
01670 char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
01671 char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
01672 char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
01673 char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
01674 char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
01675 ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
01676 syntax_title, syntax,
01677 synopsis_title, synopsis,
01678 description_title, description,
01679 arguments_title, arguments,
01680 seealso_title, seealso);
01681 ast_free(syntax);
01682 ast_free(synopsis);
01683 ast_free(description);
01684 ast_free(arguments);
01685 ast_free(seealso);
01686 } else
01687 #endif
01688 {
01689 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
01690 cur->action, cur->synopsis,
01691 authority_to_str(cur->authority, &authority),
01692 S_OR(cur->description, ""));
01693 }
01694 }
01695 }
01696 }
01697 AST_RWLIST_UNLOCK(&actions);
01698
01699 return CLI_SUCCESS;
01700 }
01701
01702 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01703 {
01704 switch (cmd) {
01705 case CLI_INIT:
01706 e->command = "manager set debug [on|off]";
01707 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
01708 return NULL;
01709 case CLI_GENERATE:
01710 return NULL;
01711 }
01712
01713 if (a->argc == 3) {
01714 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
01715 } else if (a->argc == 4) {
01716 if (!strcasecmp(a->argv[3], "on")) {
01717 manager_debug = 1;
01718 } else if (!strcasecmp(a->argv[3], "off")) {
01719 manager_debug = 0;
01720 } else {
01721 return CLI_SHOWUSAGE;
01722 }
01723 }
01724 return CLI_SUCCESS;
01725 }
01726
01727 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01728 {
01729 struct ast_manager_user *user = NULL;
01730 int l, which;
01731 char *ret = NULL;
01732 struct ast_str *rauthority = ast_str_alloca(128);
01733 struct ast_str *wauthority = ast_str_alloca(128);
01734 struct ast_variable *v;
01735
01736 switch (cmd) {
01737 case CLI_INIT:
01738 e->command = "manager show user";
01739 e->usage =
01740 " Usage: manager show user <user>\n"
01741 " Display all information related to the manager user specified.\n";
01742 return NULL;
01743 case CLI_GENERATE:
01744 l = strlen(a->word);
01745 which = 0;
01746 if (a->pos != 3) {
01747 return NULL;
01748 }
01749 AST_RWLIST_RDLOCK(&users);
01750 AST_RWLIST_TRAVERSE(&users, user, list) {
01751 if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
01752 ret = ast_strdup(user->username);
01753 break;
01754 }
01755 }
01756 AST_RWLIST_UNLOCK(&users);
01757 return ret;
01758 }
01759
01760 if (a->argc != 4) {
01761 return CLI_SHOWUSAGE;
01762 }
01763
01764 AST_RWLIST_RDLOCK(&users);
01765
01766 if (!(user = get_manager_by_name_locked(a->argv[3]))) {
01767 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
01768 AST_RWLIST_UNLOCK(&users);
01769 return CLI_SUCCESS;
01770 }
01771
01772 ast_cli(a->fd, "\n");
01773 ast_cli(a->fd,
01774 " username: %s\n"
01775 " secret: %s\n"
01776 " ACL: %s\n"
01777 " read perm: %s\n"
01778 " write perm: %s\n"
01779 "displayconnects: %s\n",
01780 (user->username ? user->username : "(N/A)"),
01781 (user->secret ? "<Set>" : "(N/A)"),
01782 ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
01783 user_authority_to_str(user->readperm, &rauthority),
01784 user_authority_to_str(user->writeperm, &wauthority),
01785 (user->displayconnects ? "yes" : "no"));
01786 ast_cli(a->fd, " Variables: \n");
01787 for (v = user->chanvars ; v ; v = v->next) {
01788 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
01789 }
01790
01791 AST_RWLIST_UNLOCK(&users);
01792
01793 return CLI_SUCCESS;
01794 }
01795
01796 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01797 {
01798 struct ast_manager_user *user = NULL;
01799 int count_amu = 0;
01800 switch (cmd) {
01801 case CLI_INIT:
01802 e->command = "manager show users";
01803 e->usage =
01804 "Usage: manager show users\n"
01805 " Prints a listing of all managers that are currently configured on that\n"
01806 " system.\n";
01807 return NULL;
01808 case CLI_GENERATE:
01809 return NULL;
01810 }
01811 if (a->argc != 3) {
01812 return CLI_SHOWUSAGE;
01813 }
01814
01815 AST_RWLIST_RDLOCK(&users);
01816
01817
01818 if (AST_RWLIST_EMPTY(&users)) {
01819 ast_cli(a->fd, "There are no manager users.\n");
01820 AST_RWLIST_UNLOCK(&users);
01821 return CLI_SUCCESS;
01822 }
01823
01824 ast_cli(a->fd, "\nusername\n--------\n");
01825
01826 AST_RWLIST_TRAVERSE(&users, user, list) {
01827 ast_cli(a->fd, "%s\n", user->username);
01828 count_amu++;
01829 }
01830
01831 AST_RWLIST_UNLOCK(&users);
01832
01833 ast_cli(a->fd,"-------------------\n"
01834 "%d manager users configured.\n", count_amu);
01835 return CLI_SUCCESS;
01836 }
01837
01838
01839 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01840 {
01841 struct manager_action *cur;
01842 struct ast_str *authority;
01843 #define HSMC_FORMAT " %-15.15s %-15.15s %-55.55s\n"
01844 switch (cmd) {
01845 case CLI_INIT:
01846 e->command = "manager show commands";
01847 e->usage =
01848 "Usage: manager show commands\n"
01849 " Prints a listing of all the available Asterisk manager interface commands.\n";
01850 return NULL;
01851 case CLI_GENERATE:
01852 return NULL;
01853 }
01854 authority = ast_str_alloca(80);
01855 ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
01856 ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
01857
01858 AST_RWLIST_RDLOCK(&actions);
01859 AST_RWLIST_TRAVERSE(&actions, cur, list) {
01860 ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
01861 }
01862 AST_RWLIST_UNLOCK(&actions);
01863
01864 return CLI_SUCCESS;
01865 }
01866
01867
01868 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01869 {
01870 struct ao2_container *sessions;
01871 struct mansession_session *session;
01872 time_t now = time(NULL);
01873 #define HSMCONN_FORMAT1 " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
01874 #define HSMCONN_FORMAT2 " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
01875 int count = 0;
01876 struct ao2_iterator i;
01877
01878 switch (cmd) {
01879 case CLI_INIT:
01880 e->command = "manager show connected";
01881 e->usage =
01882 "Usage: manager show connected\n"
01883 " Prints a listing of the users that are currently connected to the\n"
01884 "Asterisk manager interface.\n";
01885 return NULL;
01886 case CLI_GENERATE:
01887 return NULL;
01888 }
01889
01890 ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
01891
01892 sessions = ao2_global_obj_ref(mgr_sessions);
01893 if (sessions) {
01894 i = ao2_iterator_init(sessions, 0);
01895 ao2_ref(sessions, -1);
01896 while ((session = ao2_iterator_next(&i))) {
01897 ao2_lock(session);
01898 ast_cli(a->fd, HSMCONN_FORMAT2, session->username,
01899 ast_sockaddr_stringify_addr(&session->addr),
01900 (int) (session->sessionstart),
01901 (int) (now - session->sessionstart),
01902 session->fd,
01903 session->inuse,
01904 session->readperm,
01905 session->writeperm);
01906 count++;
01907 ao2_unlock(session);
01908 unref_mansession(session);
01909 }
01910 ao2_iterator_destroy(&i);
01911 }
01912 ast_cli(a->fd, "%d users connected.\n", count);
01913
01914 return CLI_SUCCESS;
01915 }
01916
01917
01918
01919 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01920 {
01921 struct eventqent *s;
01922 switch (cmd) {
01923 case CLI_INIT:
01924 e->command = "manager show eventq";
01925 e->usage =
01926 "Usage: manager show eventq\n"
01927 " Prints a listing of all events pending in the Asterisk manger\n"
01928 "event queue.\n";
01929 return NULL;
01930 case CLI_GENERATE:
01931 return NULL;
01932 }
01933 AST_RWLIST_RDLOCK(&all_events);
01934 AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
01935 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
01936 ast_cli(a->fd, "Category: %d\n", s->category);
01937 ast_cli(a->fd, "Event:\n%s", s->eventdata);
01938 }
01939 AST_RWLIST_UNLOCK(&all_events);
01940
01941 return CLI_SUCCESS;
01942 }
01943
01944
01945 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01946 {
01947 switch (cmd) {
01948 case CLI_INIT:
01949 e->command = "manager reload";
01950 e->usage =
01951 "Usage: manager reload\n"
01952 " Reloads the manager configuration.\n";
01953 return NULL;
01954 case CLI_GENERATE:
01955 return NULL;
01956 }
01957 if (a->argc > 2) {
01958 return CLI_SHOWUSAGE;
01959 }
01960 reload_manager();
01961 return CLI_SUCCESS;
01962 }
01963
01964 static struct eventqent *advance_event(struct eventqent *e)
01965 {
01966 struct eventqent *next;
01967
01968 AST_RWLIST_RDLOCK(&all_events);
01969 if ((next = AST_RWLIST_NEXT(e, eq_next))) {
01970 ast_atomic_fetchadd_int(&next->usecount, 1);
01971 ast_atomic_fetchadd_int(&e->usecount, -1);
01972 }
01973 AST_RWLIST_UNLOCK(&all_events);
01974 return next;
01975 }
01976
01977 #define GET_HEADER_FIRST_MATCH 0
01978 #define GET_HEADER_LAST_MATCH 1
01979 #define GET_HEADER_SKIP_EMPTY 2
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994 static const char *__astman_get_header(const struct message *m, char *var, int mode)
01995 {
01996 int x, l = strlen(var);
01997 const char *result = "";
01998
01999 if (!m) {
02000 return result;
02001 }
02002
02003 for (x = 0; x < m->hdrcount; x++) {
02004 const char *h = m->headers[x];
02005 if (!strncasecmp(var, h, l) && h[l] == ':') {
02006 const char *value = h + l + 1;
02007 value = ast_skip_blanks(value);
02008
02009 if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
02010 continue;
02011 }
02012 if (mode & GET_HEADER_LAST_MATCH) {
02013 result = value;
02014 } else {
02015 return value;
02016 }
02017 }
02018 }
02019
02020 return result;
02021 }
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031 const char *astman_get_header(const struct message *m, char *var)
02032 {
02033 return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH);
02034 }
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045 static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
02046 {
02047 char *parse;
02048 AST_DECLARE_APP_ARGS(args,
02049 AST_APP_ARG(vars)[64];
02050 );
02051
02052 hdr_val = ast_skip_blanks(hdr_val);
02053 parse = ast_strdupa(hdr_val);
02054
02055
02056 AST_STANDARD_APP_ARGS(args, parse);
02057 if (args.argc) {
02058 int y;
02059
02060
02061 for (y = 0; y < args.argc; y++) {
02062 struct ast_variable *cur;
02063 char *var;
02064 char *val;
02065
02066 if (!args.vars[y]) {
02067 continue;
02068 }
02069 var = val = args.vars[y];
02070 strsep(&val, "=");
02071
02072
02073 if (!val || ast_strlen_zero(var)) {
02074 continue;
02075 }
02076
02077
02078 cur = ast_variable_new(var, val, "");
02079 if (cur) {
02080 cur->next = head;
02081 head = cur;
02082 }
02083 }
02084 }
02085
02086 return head;
02087 }
02088
02089 struct ast_variable *astman_get_variables(const struct message *m)
02090 {
02091 return astman_get_variables_order(m, ORDER_REVERSE);
02092 }
02093
02094 struct ast_variable *astman_get_variables_order(const struct message *m,
02095 enum variable_orders order)
02096 {
02097 int varlen;
02098 int x;
02099 struct ast_variable *head = NULL;
02100
02101 static const char var_hdr[] = "Variable:";
02102
02103
02104 varlen = strlen(var_hdr);
02105 for (x = 0; x < m->hdrcount; x++) {
02106 if (strncasecmp(var_hdr, m->headers[x], varlen)) {
02107 continue;
02108 }
02109 head = man_do_variable_value(head, m->headers[x] + varlen);
02110 }
02111
02112 if (order == ORDER_NATURAL) {
02113 head = ast_variables_reverse(head);
02114 }
02115
02116 return head;
02117 }
02118
02119
02120 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
02121 {
02122 const char *action;
02123 int ret = 0;
02124 struct manager_action *act_found;
02125 struct mansession s = {.session = NULL, };
02126 struct message m = { 0 };
02127 char *dup_str;
02128 char *src;
02129 int x = 0;
02130 int curlen;
02131
02132 if (hook == NULL) {
02133 return -1;
02134 }
02135
02136
02137 src = dup_str = ast_strdup(msg);
02138 if (!dup_str) {
02139 return -1;
02140 }
02141
02142
02143 curlen = strlen(src);
02144 for (x = 0; x < curlen; x++) {
02145 int cr;
02146 if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
02147 cr = 2;
02148 else if (src[x] == '\n')
02149 cr = 1;
02150 else
02151 continue;
02152
02153 if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
02154
02155 src[x] = '\0';
02156 m.headers[m.hdrcount++] = src;
02157 }
02158 x += cr;
02159 curlen -= x;
02160 src += x;
02161 x = -1;
02162 }
02163
02164 action = astman_get_header(&m, "Action");
02165 if (strcasecmp(action, "login")) {
02166 act_found = action_find(action);
02167 if (act_found) {
02168
02169
02170
02171
02172
02173 s.hook = hook;
02174 s.f = (void*)1;
02175
02176 ao2_lock(act_found);
02177 if (act_found->registered && act_found->func) {
02178 if (act_found->module) {
02179 ast_module_ref(act_found->module);
02180 }
02181 ao2_unlock(act_found);
02182 ret = act_found->func(&s, &m);
02183 ao2_lock(act_found);
02184 if (act_found->module) {
02185 ast_module_unref(act_found->module);
02186 }
02187 } else {
02188 ret = -1;
02189 }
02190 ao2_unlock(act_found);
02191 ao2_t_ref(act_found, -1, "done with found action object");
02192 }
02193 }
02194 ast_free(dup_str);
02195 return ret;
02196 }
02197
02198
02199
02200
02201
02202
02203 static int send_string(struct mansession *s, char *string)
02204 {
02205 int res;
02206 FILE *f = s->f ? s->f : s->session->f;
02207 int fd = s->f ? s->fd : s->session->fd;
02208
02209
02210 if (s->hook) {
02211
02212
02213
02214
02215 s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
02216 return 0;
02217 }
02218
02219 if ((res = ast_careful_fwrite(f, fd, string, strlen(string), s->session->writetimeout))) {
02220 s->write_error = 1;
02221 }
02222
02223 return res;
02224 }
02225
02226
02227
02228
02229
02230
02231
02232
02233 AST_THREADSTORAGE(astman_append_buf);
02234
02235 AST_THREADSTORAGE(userevent_buf);
02236
02237
02238 #define ASTMAN_APPEND_BUF_INITSIZE 256
02239
02240
02241
02242
02243 void astman_append(struct mansession *s, const char *fmt, ...)
02244 {
02245 va_list ap;
02246 struct ast_str *buf;
02247
02248 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
02249 return;
02250 }
02251
02252 va_start(ap, fmt);
02253 ast_str_set_va(&buf, 0, fmt, ap);
02254 va_end(ap);
02255
02256 if (s->f != NULL || s->session->f != NULL) {
02257 send_string(s, ast_str_buffer(buf));
02258 } else {
02259 ast_verbose("fd == -1 in astman_append, should not happen\n");
02260 }
02261 }
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273 #define MSG_MOREDATA ((char *)astman_send_response)
02274
02275
02276
02277
02278
02279
02280
02281
02282 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
02283 {
02284 const char *id = astman_get_header(m, "ActionID");
02285
02286 astman_append(s, "Response: %s\r\n", resp);
02287 if (!ast_strlen_zero(id)) {
02288 astman_append(s, "ActionID: %s\r\n", id);
02289 }
02290 if (listflag) {
02291 astman_append(s, "EventList: %s\r\n", listflag);
02292 }
02293 if (msg == MSG_MOREDATA) {
02294 return;
02295 } else if (msg) {
02296 astman_append(s, "Message: %s\r\n\r\n", msg);
02297 } else {
02298 astman_append(s, "\r\n");
02299 }
02300 }
02301
02302 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
02303 {
02304 astman_send_response_full(s, m, resp, msg, NULL);
02305 }
02306
02307 void astman_send_error(struct mansession *s, const struct message *m, char *error)
02308 {
02309 astman_send_response_full(s, m, "Error", error, NULL);
02310 }
02311
02312 void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
02313 {
02314 va_list ap;
02315 struct ast_str *buf;
02316 char *msg;
02317
02318 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
02319 return;
02320 }
02321
02322 va_start(ap, fmt);
02323 ast_str_set_va(&buf, 0, fmt, ap);
02324 va_end(ap);
02325
02326
02327
02328 msg = ast_str_buffer(buf);
02329 if (msg) {
02330 msg = ast_strdupa(msg);
02331 }
02332 astman_send_response_full(s, m, "Error", msg, NULL);
02333 }
02334
02335 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
02336 {
02337 astman_send_response_full(s, m, "Success", msg, NULL);
02338 }
02339
02340 static void astman_start_ack(struct mansession *s, const struct message *m)
02341 {
02342 astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
02343 }
02344
02345 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
02346 {
02347 astman_send_response_full(s, m, "Success", msg, listflag);
02348 }
02349
02350
02351 static void mansession_lock(struct mansession *s)
02352 {
02353 ast_mutex_lock(&s->lock);
02354 }
02355
02356
02357 static void mansession_unlock(struct mansession *s)
02358 {
02359 ast_mutex_unlock(&s->lock);
02360 }
02361
02362
02363
02364
02365
02366 static int set_eventmask(struct mansession *s, const char *eventmask)
02367 {
02368 int maskint = strings_to_mask(eventmask);
02369
02370 ao2_lock(s->session);
02371 if (maskint >= 0) {
02372 s->session->send_events = maskint;
02373 }
02374 ao2_unlock(s->session);
02375
02376 return maskint;
02377 }
02378
02379 static enum ast_security_event_transport_type mansession_get_transport(const struct mansession *s)
02380 {
02381 return s->tcptls_session->parent->tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS :
02382 AST_SECURITY_EVENT_TRANSPORT_TCP;
02383 }
02384
02385 static void report_invalid_user(const struct mansession *s, const char *username)
02386 {
02387 char session_id[32];
02388 struct ast_security_event_inval_acct_id inval_acct_id = {
02389 .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
02390 .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
02391 .common.service = "AMI",
02392 .common.account_id = username,
02393 .common.session_tv = &s->session->sessionstart_tv,
02394 .common.local_addr = {
02395 .addr = &s->tcptls_session->parent->local_address,
02396 .transport = mansession_get_transport(s),
02397 },
02398 .common.remote_addr = {
02399 .addr = &s->session->addr,
02400 .transport = mansession_get_transport(s),
02401 },
02402 .common.session_id = session_id,
02403 };
02404
02405 snprintf(session_id, sizeof(session_id), "%p", s);
02406
02407 ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
02408 }
02409
02410 static void report_failed_acl(const struct mansession *s, const char *username)
02411 {
02412 char session_id[32];
02413 struct ast_security_event_failed_acl failed_acl_event = {
02414 .common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
02415 .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
02416 .common.service = "AMI",
02417 .common.account_id = username,
02418 .common.session_tv = &s->session->sessionstart_tv,
02419 .common.local_addr = {
02420 .addr = &s->tcptls_session->parent->local_address,
02421 .transport = mansession_get_transport(s),
02422 },
02423 .common.remote_addr = {
02424 .addr = &s->session->addr,
02425 .transport = mansession_get_transport(s),
02426 },
02427 .common.session_id = session_id,
02428 };
02429
02430 snprintf(session_id, sizeof(session_id), "%p", s->session);
02431
02432 ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
02433 }
02434
02435 static void report_inval_password(const struct mansession *s, const char *username)
02436 {
02437 char session_id[32];
02438 struct ast_security_event_inval_password inval_password = {
02439 .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
02440 .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
02441 .common.service = "AMI",
02442 .common.account_id = username,
02443 .common.session_tv = &s->session->sessionstart_tv,
02444 .common.local_addr = {
02445 .addr = &s->tcptls_session->parent->local_address,
02446 .transport = mansession_get_transport(s),
02447 },
02448 .common.remote_addr = {
02449 .addr = &s->session->addr,
02450 .transport = mansession_get_transport(s),
02451 },
02452 .common.session_id = session_id,
02453 };
02454
02455 snprintf(session_id, sizeof(session_id), "%p", s->session);
02456
02457 ast_security_event_report(AST_SEC_EVT(&inval_password));
02458 }
02459
02460 static void report_auth_success(const struct mansession *s)
02461 {
02462 char session_id[32];
02463 struct ast_security_event_successful_auth successful_auth = {
02464 .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
02465 .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
02466 .common.service = "AMI",
02467 .common.account_id = s->session->username,
02468 .common.session_tv = &s->session->sessionstart_tv,
02469 .common.local_addr = {
02470 .addr = &s->tcptls_session->parent->local_address,
02471 .transport = mansession_get_transport(s),
02472 },
02473 .common.remote_addr = {
02474 .addr = &s->session->addr,
02475 .transport = mansession_get_transport(s),
02476 },
02477 .common.session_id = session_id,
02478 };
02479
02480 snprintf(session_id, sizeof(session_id), "%p", s->session);
02481
02482 ast_security_event_report(AST_SEC_EVT(&successful_auth));
02483 }
02484
02485 static void report_req_not_allowed(const struct mansession *s, const char *action)
02486 {
02487 char session_id[32];
02488 char request_type[64];
02489 struct ast_security_event_req_not_allowed req_not_allowed = {
02490 .common.event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED,
02491 .common.version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
02492 .common.service = "AMI",
02493 .common.account_id = s->session->username,
02494 .common.session_tv = &s->session->sessionstart_tv,
02495 .common.local_addr = {
02496 .addr = &s->tcptls_session->parent->local_address,
02497 .transport = mansession_get_transport(s),
02498 },
02499 .common.remote_addr = {
02500 .addr = &s->session->addr,
02501 .transport = mansession_get_transport(s),
02502 },
02503 .common.session_id = session_id,
02504
02505 .request_type = request_type,
02506 };
02507
02508 snprintf(session_id, sizeof(session_id), "%p", s->session);
02509 snprintf(request_type, sizeof(request_type), "Action: %s", action);
02510
02511 ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
02512 }
02513
02514 static void report_req_bad_format(const struct mansession *s, const char *action)
02515 {
02516 char session_id[32];
02517 char request_type[64];
02518 struct ast_security_event_req_bad_format req_bad_format = {
02519 .common.event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT,
02520 .common.version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
02521 .common.service = "AMI",
02522 .common.account_id = s->session->username,
02523 .common.session_tv = &s->session->sessionstart_tv,
02524 .common.local_addr = {
02525 .addr = &s->tcptls_session->parent->local_address,
02526 .transport = mansession_get_transport(s),
02527 },
02528 .common.remote_addr = {
02529 .addr = &s->session->addr,
02530 .transport = mansession_get_transport(s),
02531 },
02532 .common.session_id = session_id,
02533
02534 .request_type = request_type,
02535 };
02536
02537 snprintf(session_id, sizeof(session_id), "%p", s->session);
02538 snprintf(request_type, sizeof(request_type), "Action: %s", action);
02539
02540 ast_security_event_report(AST_SEC_EVT(&req_bad_format));
02541 }
02542
02543 static void report_failed_challenge_response(const struct mansession *s,
02544 const char *response, const char *expected_response)
02545 {
02546 char session_id[32];
02547 struct ast_security_event_chal_resp_failed chal_resp_failed = {
02548 .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
02549 .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
02550 .common.service = "AMI",
02551 .common.account_id = s->session->username,
02552 .common.session_tv = &s->session->sessionstart_tv,
02553 .common.local_addr = {
02554 .addr = &s->tcptls_session->parent->local_address,
02555 .transport = mansession_get_transport(s),
02556 },
02557 .common.remote_addr = {
02558 .addr = &s->session->addr,
02559 .transport = mansession_get_transport(s),
02560 },
02561 .common.session_id = session_id,
02562
02563 .challenge = s->session->challenge,
02564 .response = response,
02565 .expected_response = expected_response,
02566 };
02567
02568 snprintf(session_id, sizeof(session_id), "%p", s->session);
02569
02570 ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
02571 }
02572
02573 static void report_session_limit(const struct mansession *s)
02574 {
02575 char session_id[32];
02576 struct ast_security_event_session_limit session_limit = {
02577 .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
02578 .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
02579 .common.service = "AMI",
02580 .common.account_id = s->session->username,
02581 .common.session_tv = &s->session->sessionstart_tv,
02582 .common.local_addr = {
02583 .addr = &s->tcptls_session->parent->local_address,
02584 .transport = mansession_get_transport(s),
02585 },
02586 .common.remote_addr = {
02587 .addr = &s->session->addr,
02588 .transport = mansession_get_transport(s),
02589 },
02590 .common.session_id = session_id,
02591 };
02592
02593 snprintf(session_id, sizeof(session_id), "%p", s->session);
02594
02595 ast_security_event_report(AST_SEC_EVT(&session_limit));
02596 }
02597
02598
02599
02600
02601
02602
02603
02604
02605 static int authenticate(struct mansession *s, const struct message *m)
02606 {
02607 const char *username = astman_get_header(m, "Username");
02608 const char *password = astman_get_header(m, "Secret");
02609 int error = -1;
02610 struct ast_manager_user *user = NULL;
02611 regex_t *regex_filter;
02612 struct ao2_iterator filter_iter;
02613
02614 if (ast_strlen_zero(username)) {
02615 return -1;
02616 }
02617
02618
02619 AST_RWLIST_WRLOCK(&users);
02620
02621 if (!(user = get_manager_by_name_locked(username))) {
02622 report_invalid_user(s, username);
02623 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
02624 } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
02625 report_failed_acl(s, username);
02626 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
02627 } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
02628 const char *key = astman_get_header(m, "Key");
02629 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
02630 int x;
02631 int len = 0;
02632 char md5key[256] = "";
02633 struct MD5Context md5;
02634 unsigned char digest[16];
02635
02636 MD5Init(&md5);
02637 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
02638 MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
02639 MD5Final(digest, &md5);
02640 for (x = 0; x < 16; x++)
02641 len += sprintf(md5key + len, "%2.2x", (unsigned)digest[x]);
02642 if (!strcmp(md5key, key)) {
02643 error = 0;
02644 } else {
02645 report_failed_challenge_response(s, key, md5key);
02646 }
02647 } else {
02648 ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
02649 S_OR(s->session->challenge, ""));
02650 }
02651 } else if (user->secret) {
02652 if (!strcmp(password, user->secret)) {
02653 error = 0;
02654 } else {
02655 report_inval_password(s, username);
02656 }
02657 }
02658
02659 if (error) {
02660 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
02661 AST_RWLIST_UNLOCK(&users);
02662 return -1;
02663 }
02664
02665
02666
02667
02668
02669
02670 ast_copy_string(s->session->username, username, sizeof(s->session->username));
02671 s->session->readperm = user->readperm;
02672 s->session->writeperm = user->writeperm;
02673 s->session->writetimeout = user->writetimeout;
02674 if (user->chanvars) {
02675 s->session->chanvars = ast_variables_dup(user->chanvars);
02676 }
02677
02678 filter_iter = ao2_iterator_init(user->whitefilters, 0);
02679 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
02680 ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
02681 ao2_t_ref(regex_filter, -1, "remove iterator ref");
02682 }
02683 ao2_iterator_destroy(&filter_iter);
02684
02685 filter_iter = ao2_iterator_init(user->blackfilters, 0);
02686 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
02687 ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
02688 ao2_t_ref(regex_filter, -1, "remove iterator ref");
02689 }
02690 ao2_iterator_destroy(&filter_iter);
02691
02692 s->session->sessionstart = time(NULL);
02693 s->session->sessionstart_tv = ast_tvnow();
02694 set_eventmask(s, astman_get_header(m, "Events"));
02695
02696 report_auth_success(s);
02697
02698 AST_RWLIST_UNLOCK(&users);
02699 return 0;
02700 }
02701
02702 static int action_ping(struct mansession *s, const struct message *m)
02703 {
02704 const char *actionid = astman_get_header(m, "ActionID");
02705 struct timeval now = ast_tvnow();
02706
02707 astman_append(s, "Response: Success\r\n");
02708 if (!ast_strlen_zero(actionid)){
02709 astman_append(s, "ActionID: %s\r\n", actionid);
02710 }
02711 astman_append(
02712 s,
02713 "Ping: Pong\r\n"
02714 "Timestamp: %ld.%06lu\r\n"
02715 "\r\n",
02716 (long) now.tv_sec, (unsigned long) now.tv_usec);
02717 return 0;
02718 }
02719
02720 static int action_getconfig(struct mansession *s, const struct message *m)
02721 {
02722 struct ast_config *cfg;
02723 const char *fn = astman_get_header(m, "Filename");
02724 const char *category = astman_get_header(m, "Category");
02725 int catcount = 0;
02726 int lineno = 0;
02727 char *cur_category = NULL;
02728 struct ast_variable *v;
02729 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02730
02731 if (ast_strlen_zero(fn)) {
02732 astman_send_error(s, m, "Filename not specified");
02733 return 0;
02734 }
02735 cfg = ast_config_load2(fn, "manager", config_flags);
02736 if (cfg == CONFIG_STATUS_FILEMISSING) {
02737 astman_send_error(s, m, "Config file not found");
02738 return 0;
02739 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02740 astman_send_error(s, m, "Config file has invalid format");
02741 return 0;
02742 }
02743
02744 astman_start_ack(s, m);
02745 while ((cur_category = ast_category_browse(cfg, cur_category))) {
02746 if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
02747 lineno = 0;
02748 astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
02749 for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
02750 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
02751 }
02752 catcount++;
02753 }
02754 }
02755 if (!ast_strlen_zero(category) && catcount == 0) {
02756 astman_append(s, "No categories found\r\n");
02757 }
02758 ast_config_destroy(cfg);
02759 astman_append(s, "\r\n");
02760
02761 return 0;
02762 }
02763
02764 static int action_listcategories(struct mansession *s, const struct message *m)
02765 {
02766 struct ast_config *cfg;
02767 const char *fn = astman_get_header(m, "Filename");
02768 char *category = NULL;
02769 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02770 int catcount = 0;
02771
02772 if (ast_strlen_zero(fn)) {
02773 astman_send_error(s, m, "Filename not specified");
02774 return 0;
02775 }
02776 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
02777 astman_send_error(s, m, "Config file not found");
02778 return 0;
02779 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02780 astman_send_error(s, m, "Config file has invalid format");
02781 return 0;
02782 }
02783 astman_start_ack(s, m);
02784 while ((category = ast_category_browse(cfg, category))) {
02785 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
02786 catcount++;
02787 }
02788 if (catcount == 0) {
02789 astman_append(s, "Error: no categories found\r\n");
02790 }
02791 ast_config_destroy(cfg);
02792 astman_append(s, "\r\n");
02793
02794 return 0;
02795 }
02796
02797
02798
02799
02800
02801 static void json_escape(char *out, const char *in)
02802 {
02803 for (; *in; in++) {
02804 if (*in == '\\' || *in == '\"') {
02805 *out++ = '\\';
02806 }
02807 *out++ = *in;
02808 }
02809 *out = '\0';
02810 }
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820
02821 static void astman_append_json(struct mansession *s, const char *str)
02822 {
02823 char *buf;
02824
02825 buf = ast_alloca(2 * strlen(str) + 1);
02826 json_escape(buf, str);
02827 astman_append(s, "%s", buf);
02828 }
02829
02830 static int action_getconfigjson(struct mansession *s, const struct message *m)
02831 {
02832 struct ast_config *cfg;
02833 const char *fn = astman_get_header(m, "Filename");
02834 char *category = NULL;
02835 struct ast_variable *v;
02836 int comma1 = 0;
02837 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
02838
02839 if (ast_strlen_zero(fn)) {
02840 astman_send_error(s, m, "Filename not specified");
02841 return 0;
02842 }
02843
02844 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
02845 astman_send_error(s, m, "Config file not found");
02846 return 0;
02847 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02848 astman_send_error(s, m, "Config file has invalid format");
02849 return 0;
02850 }
02851
02852 astman_start_ack(s, m);
02853 astman_append(s, "JSON: {");
02854 while ((category = ast_category_browse(cfg, category))) {
02855 int comma2 = 0;
02856
02857 astman_append(s, "%s\"", comma1 ? "," : "");
02858 astman_append_json(s, category);
02859 astman_append(s, "\":[");
02860 comma1 = 1;
02861 for (v = ast_variable_browse(cfg, category); v; v = v->next) {
02862 astman_append(s, "%s\"", comma2 ? "," : "");
02863 astman_append_json(s, v->name);
02864 astman_append(s, "\":\"");
02865 astman_append_json(s, v->value);
02866 astman_append(s, "\"");
02867 comma2 = 1;
02868 }
02869 astman_append(s, "]");
02870 }
02871 astman_append(s, "}\r\n\r\n");
02872
02873 ast_config_destroy(cfg);
02874
02875 return 0;
02876 }
02877
02878
02879 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
02880 {
02881 int x;
02882 char hdr[40];
02883 const char *action, *cat, *var, *value, *match, *line;
02884 struct ast_category *category;
02885 struct ast_variable *v;
02886 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
02887 enum error_type result = 0;
02888
02889 for (x = 0; x < 100000; x++) {
02890 unsigned int object = 0;
02891
02892 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
02893 action = astman_get_header(m, hdr);
02894 if (ast_strlen_zero(action))
02895 break;
02896
02897 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
02898 cat = astman_get_header(m, hdr);
02899 if (ast_strlen_zero(cat)) {
02900 result = UNSPECIFIED_CATEGORY;
02901 break;
02902 }
02903
02904 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
02905 var = astman_get_header(m, hdr);
02906
02907 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
02908 value = astman_get_header(m, hdr);
02909
02910 if (!ast_strlen_zero(value) && *value == '>') {
02911 object = 1;
02912 value++;
02913 }
02914
02915 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
02916 match = astman_get_header(m, hdr);
02917
02918 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
02919 line = astman_get_header(m, hdr);
02920
02921 if (!strcasecmp(action, "newcat")) {
02922 if (ast_category_get(cfg,cat)) {
02923 result = FAILURE_NEWCAT;
02924 break;
02925 }
02926 if (!(category = ast_category_new(cat, dfn, -1))) {
02927 result = FAILURE_ALLOCATION;
02928 break;
02929 }
02930 if (ast_strlen_zero(match)) {
02931 ast_category_append(cfg, category);
02932 } else {
02933 ast_category_insert(cfg, category, match);
02934 }
02935 } else if (!strcasecmp(action, "renamecat")) {
02936 if (ast_strlen_zero(value)) {
02937 result = UNSPECIFIED_ARGUMENT;
02938 break;
02939 }
02940 if (!(category = ast_category_get(cfg, cat))) {
02941 result = UNKNOWN_CATEGORY;
02942 break;
02943 }
02944 ast_category_rename(category, value);
02945 } else if (!strcasecmp(action, "delcat")) {
02946 if (ast_category_delete(cfg, cat)) {
02947 result = FAILURE_DELCAT;
02948 break;
02949 }
02950 } else if (!strcasecmp(action, "emptycat")) {
02951 if (ast_category_empty(cfg, cat)) {
02952 result = FAILURE_EMPTYCAT;
02953 break;
02954 }
02955 } else if (!strcasecmp(action, "update")) {
02956 if (ast_strlen_zero(var)) {
02957 result = UNSPECIFIED_ARGUMENT;
02958 break;
02959 }
02960 if (!(category = ast_category_get(cfg,cat))) {
02961 result = UNKNOWN_CATEGORY;
02962 break;
02963 }
02964 if (ast_variable_update(category, var, value, match, object)) {
02965 result = FAILURE_UPDATE;
02966 break;
02967 }
02968 } else if (!strcasecmp(action, "delete")) {
02969 if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
02970 result = UNSPECIFIED_ARGUMENT;
02971 break;
02972 }
02973 if (!(category = ast_category_get(cfg, cat))) {
02974 result = UNKNOWN_CATEGORY;
02975 break;
02976 }
02977 if (ast_variable_delete(category, var, match, line)) {
02978 result = FAILURE_DELETE;
02979 break;
02980 }
02981 } else if (!strcasecmp(action, "append")) {
02982 if (ast_strlen_zero(var)) {
02983 result = UNSPECIFIED_ARGUMENT;
02984 break;
02985 }
02986 if (!(category = ast_category_get(cfg, cat))) {
02987 result = UNKNOWN_CATEGORY;
02988 break;
02989 }
02990 if (!(v = ast_variable_new(var, value, dfn))) {
02991 result = FAILURE_ALLOCATION;
02992 break;
02993 }
02994 if (object || (match && !strcasecmp(match, "object"))) {
02995 v->object = 1;
02996 }
02997 ast_variable_append(category, v);
02998 } else if (!strcasecmp(action, "insert")) {
02999 if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
03000 result = UNSPECIFIED_ARGUMENT;
03001 break;
03002 }
03003 if (!(category = ast_category_get(cfg, cat))) {
03004 result = UNKNOWN_CATEGORY;
03005 break;
03006 }
03007 if (!(v = ast_variable_new(var, value, dfn))) {
03008 result = FAILURE_ALLOCATION;
03009 break;
03010 }
03011 ast_variable_insert(category, v, line);
03012 }
03013 else {
03014 ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
03015 result = UNKNOWN_ACTION;
03016 break;
03017 }
03018 }
03019 ast_free(str1);
03020 ast_free(str2);
03021 return result;
03022 }
03023
03024 static int action_updateconfig(struct mansession *s, const struct message *m)
03025 {
03026 struct ast_config *cfg;
03027 const char *sfn = astman_get_header(m, "SrcFilename");
03028 const char *dfn = astman_get_header(m, "DstFilename");
03029 int res;
03030 const char *rld = astman_get_header(m, "Reload");
03031 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
03032 enum error_type result;
03033
03034 if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
03035 astman_send_error(s, m, "Filename not specified");
03036 return 0;
03037 }
03038 if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
03039 astman_send_error(s, m, "Config file not found");
03040 return 0;
03041 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
03042 astman_send_error(s, m, "Config file has invalid format");
03043 return 0;
03044 }
03045 result = handle_updates(s, m, cfg, dfn);
03046 if (!result) {
03047 ast_include_rename(cfg, sfn, dfn);
03048 res = ast_config_text_file_save(dfn, cfg, "Manager");
03049 ast_config_destroy(cfg);
03050 if (res) {
03051 astman_send_error(s, m, "Save of config failed");
03052 return 0;
03053 }
03054 astman_send_ack(s, m, NULL);
03055 if (!ast_strlen_zero(rld)) {
03056 if (ast_true(rld)) {
03057 rld = NULL;
03058 }
03059 ast_module_reload(rld);
03060 }
03061 } else {
03062 ast_config_destroy(cfg);
03063 switch(result) {
03064 case UNKNOWN_ACTION:
03065 astman_send_error(s, m, "Unknown action command");
03066 break;
03067 case UNKNOWN_CATEGORY:
03068 astman_send_error(s, m, "Given category does not exist");
03069 break;
03070 case UNSPECIFIED_CATEGORY:
03071 astman_send_error(s, m, "Category not specified");
03072 break;
03073 case UNSPECIFIED_ARGUMENT:
03074 astman_send_error(s, m, "Problem with category, value, or line (if required)");
03075 break;
03076 case FAILURE_ALLOCATION:
03077 astman_send_error(s, m, "Memory allocation failure, this should not happen");
03078 break;
03079 case FAILURE_NEWCAT:
03080 astman_send_error(s, m, "Create category did not complete successfully");
03081 break;
03082 case FAILURE_DELCAT:
03083 astman_send_error(s, m, "Delete category did not complete successfully");
03084 break;
03085 case FAILURE_EMPTYCAT:
03086 astman_send_error(s, m, "Empty category did not complete successfully");
03087 break;
03088 case FAILURE_UPDATE:
03089 astman_send_error(s, m, "Update did not complete successfully");
03090 break;
03091 case FAILURE_DELETE:
03092 astman_send_error(s, m, "Delete did not complete successfully");
03093 break;
03094 case FAILURE_APPEND:
03095 astman_send_error(s, m, "Append did not complete successfully");
03096 break;
03097 }
03098 }
03099 return 0;
03100 }
03101
03102 static int action_createconfig(struct mansession *s, const struct message *m)
03103 {
03104 int fd;
03105 const char *fn = astman_get_header(m, "Filename");
03106 struct ast_str *filepath = ast_str_alloca(PATH_MAX);
03107 ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
03108 ast_str_append(&filepath, 0, "%s", fn);
03109
03110 if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
03111 close(fd);
03112 astman_send_ack(s, m, "New configuration file created successfully");
03113 } else {
03114 astman_send_error(s, m, strerror(errno));
03115 }
03116
03117 return 0;
03118 }
03119
03120 static int action_waitevent(struct mansession *s, const struct message *m)
03121 {
03122 const char *timeouts = astman_get_header(m, "Timeout");
03123 int timeout = -1;
03124 int x;
03125 int needexit = 0;
03126 const char *id = astman_get_header(m, "ActionID");
03127 char idText[256];
03128
03129 if (!ast_strlen_zero(id)) {
03130 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03131 } else {
03132 idText[0] = '\0';
03133 }
03134
03135 if (!ast_strlen_zero(timeouts)) {
03136 sscanf(timeouts, "%30i", &timeout);
03137 if (timeout < -1) {
03138 timeout = -1;
03139 }
03140
03141 }
03142
03143 ao2_lock(s->session);
03144 if (s->session->waiting_thread != AST_PTHREADT_NULL) {
03145 pthread_kill(s->session->waiting_thread, SIGURG);
03146 }
03147
03148 if (s->session->managerid) {
03149
03150
03151
03152
03153
03154 time_t now = time(NULL);
03155 int max = s->session->sessiontimeout - now - 10;
03156
03157 if (max < 0) {
03158 max = 0;
03159 }
03160 if (timeout < 0 || timeout > max) {
03161 timeout = max;
03162 }
03163 if (!s->session->send_events) {
03164 s->session->send_events = -1;
03165 }
03166 }
03167 ao2_unlock(s->session);
03168
03169
03170 s->session->waiting_thread = pthread_self();
03171 ast_debug(1, "Starting waiting for an event!\n");
03172
03173 for (x = 0; x < timeout || timeout < 0; x++) {
03174 ao2_lock(s->session);
03175 if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
03176 needexit = 1;
03177 }
03178
03179
03180
03181
03182 if (s->session->waiting_thread != pthread_self()) {
03183 needexit = 1;
03184 }
03185 if (s->session->needdestroy) {
03186 needexit = 1;
03187 }
03188 ao2_unlock(s->session);
03189 if (needexit) {
03190 break;
03191 }
03192 if (s->session->managerid == 0) {
03193 if (ast_wait_for_input(s->session->fd, 1000)) {
03194 break;
03195 }
03196 } else {
03197 sleep(1);
03198 }
03199 }
03200 ast_debug(1, "Finished waiting for an event!\n");
03201
03202 ao2_lock(s->session);
03203 if (s->session->waiting_thread == pthread_self()) {
03204 struct eventqent *eqe = s->session->last_ev;
03205 astman_send_response(s, m, "Success", "Waiting for Event completed.");
03206 while ((eqe = advance_event(eqe))) {
03207 if (((s->session->readperm & eqe->category) == eqe->category) &&
03208 ((s->session->send_events & eqe->category) == eqe->category)) {
03209 astman_append(s, "%s", eqe->eventdata);
03210 }
03211 s->session->last_ev = eqe;
03212 }
03213 astman_append(s,
03214 "Event: WaitEventComplete\r\n"
03215 "%s"
03216 "\r\n", idText);
03217 s->session->waiting_thread = AST_PTHREADT_NULL;
03218 } else {
03219 ast_debug(1, "Abandoning event request!\n");
03220 }
03221 ao2_unlock(s->session);
03222
03223 return 0;
03224 }
03225
03226 static int action_listcommands(struct mansession *s, const struct message *m)
03227 {
03228 struct manager_action *cur;
03229 struct ast_str *temp = ast_str_alloca(256);
03230
03231 astman_start_ack(s, m);
03232 AST_RWLIST_RDLOCK(&actions);
03233 AST_RWLIST_TRAVERSE(&actions, cur, list) {
03234 if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
03235 astman_append(s, "%s: %s (Priv: %s)\r\n",
03236 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
03237 }
03238 }
03239 AST_RWLIST_UNLOCK(&actions);
03240 astman_append(s, "\r\n");
03241
03242 return 0;
03243 }
03244
03245 static int action_events(struct mansession *s, const struct message *m)
03246 {
03247 const char *mask = astman_get_header(m, "EventMask");
03248 int res, x;
03249 const char *id = astman_get_header(m, "ActionID");
03250 char id_text[256];
03251
03252 if (!ast_strlen_zero(id)) {
03253 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
03254 } else {
03255 id_text[0] = '\0';
03256 }
03257
03258 res = set_eventmask(s, mask);
03259 if (broken_events_action) {
03260
03261
03262
03263 if (res > 0) {
03264 for (x = 0; x < ARRAY_LEN(perms); x++) {
03265 if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
03266 return 0;
03267 }
03268 }
03269 astman_append(s, "Response: Success\r\n%s"
03270 "Events: On\r\n\r\n", id_text);
03271 } else if (res == 0)
03272 astman_append(s, "Response: Success\r\n%s"
03273 "Events: Off\r\n\r\n", id_text);
03274 return 0;
03275 }
03276
03277 if (res > 0)
03278 astman_append(s, "Response: Success\r\n%s"
03279 "Events: On\r\n\r\n", id_text);
03280 else if (res == 0)
03281 astman_append(s, "Response: Success\r\n%s"
03282 "Events: Off\r\n\r\n", id_text);
03283 else
03284 astman_send_error(s, m, "Invalid event mask");
03285
03286 return 0;
03287 }
03288
03289 static int action_logoff(struct mansession *s, const struct message *m)
03290 {
03291 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
03292 return -1;
03293 }
03294
03295 static int action_login(struct mansession *s, const struct message *m)
03296 {
03297
03298
03299 if (s->session->authenticated) {
03300 astman_send_ack(s, m, "Already authenticated");
03301 return 0;
03302 }
03303
03304 if (authenticate(s, m)) {
03305 sleep(1);
03306 astman_send_error(s, m, "Authentication failed");
03307 return -1;
03308 }
03309 s->session->authenticated = 1;
03310 ast_atomic_fetchadd_int(&unauth_sessions, -1);
03311 if (manager_displayconnects(s->session)) {
03312 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr));
03313 }
03314 astman_send_ack(s, m, "Authentication accepted");
03315 if ((s->session->send_events & EVENT_FLAG_SYSTEM)
03316 && ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
03317 struct ast_str *auth = ast_str_alloca(80);
03318 const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
03319 astman_append(s, "Event: FullyBooted\r\n"
03320 "Privilege: %s\r\n"
03321 "Status: Fully Booted\r\n\r\n", cat_str);
03322 }
03323 return 0;
03324 }
03325
03326 static int action_challenge(struct mansession *s, const struct message *m)
03327 {
03328 const char *authtype = astman_get_header(m, "AuthType");
03329
03330 if (!strcasecmp(authtype, "MD5")) {
03331 if (ast_strlen_zero(s->session->challenge)) {
03332 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
03333 }
03334 mansession_lock(s);
03335 astman_start_ack(s, m);
03336 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
03337 mansession_unlock(s);
03338 } else {
03339 astman_send_error(s, m, "Must specify AuthType");
03340 }
03341 return 0;
03342 }
03343
03344 static int action_hangup(struct mansession *s, const struct message *m)
03345 {
03346 struct ast_channel *c = NULL;
03347 int causecode = 0;
03348 const char *id = astman_get_header(m, "ActionID");
03349 const char *name_or_regex = astman_get_header(m, "Channel");
03350 const char *cause = astman_get_header(m, "Cause");
03351 char idText[256];
03352 regex_t regexbuf;
03353 struct ast_channel_iterator *iter = NULL;
03354 struct ast_str *regex_string;
03355 int channels_matched = 0;
03356
03357 if (ast_strlen_zero(name_or_regex)) {
03358 astman_send_error(s, m, "No channel specified");
03359 return 0;
03360 }
03361
03362 if (!ast_strlen_zero(id)) {
03363 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03364 } else {
03365 idText[0] = '\0';
03366 }
03367
03368 if (!ast_strlen_zero(cause)) {
03369 char *endptr;
03370 causecode = strtol(cause, &endptr, 10);
03371 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
03372 ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
03373
03374 causecode = 0;
03375 }
03376 }
03377
03378
03379
03380
03381 if (name_or_regex[0] != '/') {
03382 if (!(c = ast_channel_get_by_name(name_or_regex))) {
03383 ast_log(LOG_NOTICE, "Request to hangup non-existent channel: %s\n",
03384 name_or_regex);
03385 astman_send_error(s, m, "No such channel");
03386 return 0;
03387 }
03388
03389 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
03390 (s->session->managerid ? "HTTP " : ""),
03391 s->session->username,
03392 ast_sockaddr_stringify_addr(&s->session->addr),
03393 ast_channel_name(c));
03394
03395 ast_channel_softhangup_withcause_locked(c, causecode);
03396 c = ast_channel_unref(c);
03397
03398 astman_send_ack(s, m, "Channel Hungup");
03399
03400 return 0;
03401 }
03402
03403
03404
03405
03406 regex_string = ast_str_create(strlen(name_or_regex));
03407 if (!regex_string) {
03408 astman_send_error(s, m, "Memory Allocation Failure");
03409 return 0;
03410 }
03411
03412
03413 if (ast_regex_string_to_regex_pattern(name_or_regex, ®ex_string) != 0) {
03414 astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
03415 ast_free(regex_string);
03416 return 0;
03417 }
03418
03419
03420 if (regcomp(®exbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
03421 astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
03422 ast_free(regex_string);
03423 return 0;
03424 }
03425
03426 astman_send_listack(s, m, "Channels hung up will follow", "start");
03427
03428 iter = ast_channel_iterator_all_new();
03429 if (iter) {
03430 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
03431 if (regexec(®exbuf, ast_channel_name(c), 0, NULL, 0)) {
03432 continue;
03433 }
03434
03435 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
03436 (s->session->managerid ? "HTTP " : ""),
03437 s->session->username,
03438 ast_sockaddr_stringify_addr(&s->session->addr),
03439 ast_channel_name(c));
03440
03441 ast_channel_softhangup_withcause_locked(c, causecode);
03442 channels_matched++;
03443
03444 astman_append(s,
03445 "Event: ChannelHungup\r\n"
03446 "Channel: %s\r\n"
03447 "%s"
03448 "\r\n", ast_channel_name(c), idText);
03449 }
03450 ast_channel_iterator_destroy(iter);
03451 }
03452
03453 regfree(®exbuf);
03454 ast_free(regex_string);
03455
03456 astman_append(s,
03457 "Event: ChannelsHungupListComplete\r\n"
03458 "EventList: Complete\r\n"
03459 "ListItems: %d\r\n"
03460 "%s"
03461 "\r\n", channels_matched, idText);
03462
03463 return 0;
03464 }
03465
03466 static int action_setvar(struct mansession *s, const struct message *m)
03467 {
03468 struct ast_channel *c = NULL;
03469 const char *name = astman_get_header(m, "Channel");
03470 const char *varname = astman_get_header(m, "Variable");
03471 const char *varval = astman_get_header(m, "Value");
03472 int res = 0;
03473
03474 if (ast_strlen_zero(varname)) {
03475 astman_send_error(s, m, "No variable specified");
03476 return 0;
03477 }
03478
03479 if (!ast_strlen_zero(name)) {
03480 if (!(c = ast_channel_get_by_name(name))) {
03481 astman_send_error(s, m, "No such channel");
03482 return 0;
03483 }
03484 }
03485
03486 res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
03487
03488 if (c) {
03489 c = ast_channel_unref(c);
03490 }
03491 if (res == 0) {
03492 astman_send_ack(s, m, "Variable Set");
03493 } else {
03494 astman_send_error(s, m, "Variable not set");
03495 }
03496 return 0;
03497 }
03498
03499 static int action_getvar(struct mansession *s, const struct message *m)
03500 {
03501 struct ast_channel *c = NULL;
03502 const char *name = astman_get_header(m, "Channel");
03503 const char *varname = astman_get_header(m, "Variable");
03504 char *varval;
03505 char workspace[1024];
03506
03507 if (ast_strlen_zero(varname)) {
03508 astman_send_error(s, m, "No variable specified");
03509 return 0;
03510 }
03511
03512
03513 if (!(function_capable_string_allowed_with_auths(varname, s->session->writeperm))) {
03514 astman_send_error(s, m, "GetVar Access Forbidden: Variable");
03515 return 0;
03516 }
03517
03518 if (!ast_strlen_zero(name)) {
03519 if (!(c = ast_channel_get_by_name(name))) {
03520 astman_send_error(s, m, "No such channel");
03521 return 0;
03522 }
03523 }
03524
03525 workspace[0] = '\0';
03526 if (varname[strlen(varname) - 1] == ')') {
03527 if (!c) {
03528 c = ast_dummy_channel_alloc();
03529 if (c) {
03530 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
03531 } else
03532 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
03533 } else {
03534 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
03535 }
03536 varval = workspace;
03537 } else {
03538 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
03539 }
03540
03541 if (c) {
03542 c = ast_channel_unref(c);
03543 }
03544
03545 astman_start_ack(s, m);
03546 astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
03547
03548 return 0;
03549 }
03550
03551
03552
03553 static int action_status(struct mansession *s, const struct message *m)
03554 {
03555 const char *name = astman_get_header(m, "Channel");
03556 const char *cvariables = astman_get_header(m, "Variables");
03557 char *variables = ast_strdupa(S_OR(cvariables, ""));
03558 struct ast_channel *c;
03559 char bridge[256];
03560 struct timeval now = ast_tvnow();
03561 long elapsed_seconds = 0;
03562 int channels = 0;
03563 int all = ast_strlen_zero(name);
03564 const char *id = astman_get_header(m, "ActionID");
03565 char idText[256];
03566 AST_DECLARE_APP_ARGS(vars,
03567 AST_APP_ARG(name)[100];
03568 );
03569 struct ast_str *str = ast_str_create(1000);
03570 struct ast_channel_iterator *iter = NULL;
03571
03572 if (!ast_strlen_zero(id)) {
03573 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
03574 } else {
03575 idText[0] = '\0';
03576 }
03577
03578 if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) {
03579 astman_send_error(s, m, "Status Access Forbidden: Variables");
03580 return 0;
03581 }
03582
03583 if (all) {
03584 if (!(iter = ast_channel_iterator_all_new())) {
03585 ast_free(str);
03586 astman_send_error(s, m, "Memory Allocation Failure");
03587 return 1;
03588 }
03589 c = ast_channel_iterator_next(iter);
03590 } else {
03591 if (!(c = ast_channel_get_by_name(name))) {
03592 astman_send_error(s, m, "No such channel");
03593 ast_free(str);
03594 return 0;
03595 }
03596 }
03597
03598 astman_send_ack(s, m, "Channel status will follow");
03599
03600 if (!ast_strlen_zero(cvariables)) {
03601 AST_STANDARD_APP_ARGS(vars, variables);
03602 }
03603
03604
03605 for (; c; c = ast_channel_iterator_next(iter)) {
03606 ast_channel_lock(c);
03607
03608 if (!ast_strlen_zero(cvariables)) {
03609 int i;
03610 ast_str_reset(str);
03611 for (i = 0; i < vars.argc; i++) {
03612 char valbuf[512], *ret = NULL;
03613
03614 if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
03615 if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
03616 valbuf[0] = '\0';
03617 }
03618 ret = valbuf;
03619 } else {
03620 pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
03621 }
03622
03623 ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
03624 }
03625 }
03626
03627 channels++;
03628 if (ast_channel_internal_bridged_channel(c)) {
03629 snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", ast_channel_name(ast_channel_internal_bridged_channel(c)), ast_channel_uniqueid(ast_channel_internal_bridged_channel(c)));
03630 } else {
03631 bridge[0] = '\0';
03632 }
03633 if (ast_channel_pbx(c)) {
03634 if (ast_channel_cdr(c)) {
03635 elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
03636 }
03637 astman_append(s,
03638 "Event: Status\r\n"
03639 "Privilege: Call\r\n"
03640 "Channel: %s\r\n"
03641 "CallerIDNum: %s\r\n"
03642 "CallerIDName: %s\r\n"
03643 "ConnectedLineNum: %s\r\n"
03644 "ConnectedLineName: %s\r\n"
03645 "Accountcode: %s\r\n"
03646 "ChannelState: %u\r\n"
03647 "ChannelStateDesc: %s\r\n"
03648 "Context: %s\r\n"
03649 "Extension: %s\r\n"
03650 "Priority: %d\r\n"
03651 "Seconds: %ld\r\n"
03652 "%s"
03653 "Uniqueid: %s\r\n"
03654 "%s"
03655 "%s"
03656 "\r\n",
03657 ast_channel_name(c),
03658 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
03659 S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
03660 S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
03661 S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
03662 ast_channel_accountcode(c),
03663 ast_channel_state(c),
03664 ast_state2str(ast_channel_state(c)), ast_channel_context(c),
03665 ast_channel_exten(c), ast_channel_priority(c), (long)elapsed_seconds, bridge, ast_channel_uniqueid(c), ast_str_buffer(str), idText);
03666 } else {
03667 astman_append(s,
03668 "Event: Status\r\n"
03669 "Privilege: Call\r\n"
03670 "Channel: %s\r\n"
03671 "CallerIDNum: %s\r\n"
03672 "CallerIDName: %s\r\n"
03673 "ConnectedLineNum: %s\r\n"
03674 "ConnectedLineName: %s\r\n"
03675 "Account: %s\r\n"
03676 "State: %s\r\n"
03677 "%s"
03678 "Uniqueid: %s\r\n"
03679 "%s"
03680 "%s"
03681 "\r\n",
03682 ast_channel_name(c),
03683 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
03684 S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
03685 S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
03686 S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
03687 ast_channel_accountcode(c),
03688 ast_state2str(ast_channel_state(c)), bridge, ast_channel_uniqueid(c),
03689 ast_str_buffer(str), idText);
03690 }
03691
03692 ast_channel_unlock(c);
03693 c = ast_channel_unref(c);
03694
03695 if (!all) {
03696 break;
03697 }
03698 }
03699
03700 if (iter) {
03701 ast_channel_iterator_destroy(iter);
03702 }
03703
03704 astman_append(s,
03705 "Event: StatusComplete\r\n"
03706 "%s"
03707 "Items: %d\r\n"
03708 "\r\n", idText, channels);
03709
03710 ast_free(str);
03711
03712 return 0;
03713 }
03714
03715 static int action_sendtext(struct mansession *s, const struct message *m)
03716 {
03717 struct ast_channel *c = NULL;
03718 const char *name = astman_get_header(m, "Channel");
03719 const char *textmsg = astman_get_header(m, "Message");
03720 int res = 0;
03721
03722 if (ast_strlen_zero(name)) {
03723 astman_send_error(s, m, "No channel specified");
03724 return 0;
03725 }
03726
03727 if (ast_strlen_zero(textmsg)) {
03728 astman_send_error(s, m, "No Message specified");
03729 return 0;
03730 }
03731
03732 if (!(c = ast_channel_get_by_name(name))) {
03733 astman_send_error(s, m, "No such channel");
03734 return 0;
03735 }
03736
03737 res = ast_sendtext(c, textmsg);
03738 c = ast_channel_unref(c);
03739
03740 if (res >= 0) {
03741 astman_send_ack(s, m, "Success");
03742 } else {
03743 astman_send_error(s, m, "Failure");
03744 }
03745
03746 return 0;
03747 }
03748
03749
03750 static int action_redirect(struct mansession *s, const struct message *m)
03751 {
03752 char buf[256];
03753 const char *name = astman_get_header(m, "Channel");
03754 const char *name2 = astman_get_header(m, "ExtraChannel");
03755 const char *exten = astman_get_header(m, "Exten");
03756 const char *exten2 = astman_get_header(m, "ExtraExten");
03757 const char *context = astman_get_header(m, "Context");
03758 const char *context2 = astman_get_header(m, "ExtraContext");
03759 const char *priority = astman_get_header(m, "Priority");
03760 const char *priority2 = astman_get_header(m, "ExtraPriority");
03761 struct ast_channel *chan;
03762 struct ast_channel *chan2;
03763 int pi = 0;
03764 int pi2 = 0;
03765 int res;
03766
03767 if (ast_strlen_zero(name)) {
03768 astman_send_error(s, m, "Channel not specified");
03769 return 0;
03770 }
03771
03772 if (ast_strlen_zero(context)) {
03773 astman_send_error(s, m, "Context not specified");
03774 return 0;
03775 }
03776 if (ast_strlen_zero(exten)) {
03777 astman_send_error(s, m, "Exten not specified");
03778 return 0;
03779 }
03780 if (ast_strlen_zero(priority)) {
03781 astman_send_error(s, m, "Priority not specified");
03782 return 0;
03783 }
03784 if (sscanf(priority, "%30d", &pi) != 1) {
03785 pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
03786 }
03787 if (pi < 1) {
03788 astman_send_error(s, m, "Priority is invalid");
03789 return 0;
03790 }
03791
03792 if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
03793
03794 if (ast_strlen_zero(exten2)) {
03795 astman_send_error(s, m, "ExtraExten not specified");
03796 return 0;
03797 }
03798 if (ast_strlen_zero(priority2)) {
03799 astman_send_error(s, m, "ExtraPriority not specified");
03800 return 0;
03801 }
03802 if (sscanf(priority2, "%30d", &pi2) != 1) {
03803 pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
03804 }
03805 if (pi2 < 1) {
03806 astman_send_error(s, m, "ExtraPriority is invalid");
03807 return 0;
03808 }
03809 }
03810
03811 chan = ast_channel_get_by_name(name);
03812 if (!chan) {
03813 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
03814 astman_send_error(s, m, buf);
03815 return 0;
03816 }
03817 if (ast_check_hangup_locked(chan)) {
03818 astman_send_error(s, m, "Redirect failed, channel not up.");
03819 chan = ast_channel_unref(chan);
03820 return 0;
03821 }
03822
03823 if (ast_strlen_zero(name2)) {
03824
03825 if (ast_channel_pbx(chan)) {
03826 ast_channel_lock(chan);
03827
03828 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
03829 ast_channel_unlock(chan);
03830 }
03831 res = ast_async_goto(chan, context, exten, pi);
03832 if (!res) {
03833 astman_send_ack(s, m, "Redirect successful");
03834 } else {
03835 astman_send_error(s, m, "Redirect failed");
03836 }
03837 chan = ast_channel_unref(chan);
03838 return 0;
03839 }
03840
03841 chan2 = ast_channel_get_by_name(name2);
03842 if (!chan2) {
03843 snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
03844 astman_send_error(s, m, buf);
03845 chan = ast_channel_unref(chan);
03846 return 0;
03847 }
03848 if (ast_check_hangup_locked(chan2)) {
03849 astman_send_error(s, m, "Redirect failed, extra channel not up.");
03850 chan2 = ast_channel_unref(chan2);
03851 chan = ast_channel_unref(chan);
03852 return 0;
03853 }
03854
03855
03856 if (ast_channel_pbx(chan)) {
03857 ast_channel_lock(chan);
03858
03859 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT
03860 | AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
03861 ast_channel_unlock(chan);
03862 }
03863 if (ast_channel_pbx(chan2)) {
03864 ast_channel_lock(chan2);
03865
03866 ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT
03867 | AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
03868 ast_channel_unlock(chan2);
03869 }
03870 res = ast_async_goto(chan, context, exten, pi);
03871 if (!res) {
03872 if (!ast_strlen_zero(context2)) {
03873 res = ast_async_goto(chan2, context2, exten2, pi2);
03874 } else {
03875 res = ast_async_goto(chan2, context, exten, pi);
03876 }
03877 if (!res) {
03878 astman_send_ack(s, m, "Dual Redirect successful");
03879 } else {
03880 astman_send_error(s, m, "Secondary redirect failed");
03881 }
03882 } else {
03883 astman_send_error(s, m, "Redirect failed");
03884 }
03885
03886
03887 if (ast_channel_pbx(chan)) {
03888 ast_channel_lock(chan);
03889 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
03890 ast_channel_unlock(chan);
03891 }
03892 if (ast_channel_pbx(chan2)) {
03893 ast_channel_lock(chan2);
03894 ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
03895 ast_channel_unlock(chan2);
03896 }
03897
03898 chan2 = ast_channel_unref(chan2);
03899 chan = ast_channel_unref(chan);
03900 return 0;
03901 }
03902
03903 static int action_atxfer(struct mansession *s, const struct message *m)
03904 {
03905 const char *name = astman_get_header(m, "Channel");
03906 const char *exten = astman_get_header(m, "Exten");
03907 const char *context = astman_get_header(m, "Context");
03908 struct ast_channel *chan = NULL;
03909 struct ast_call_feature *atxfer_feature = NULL;
03910 char *feature_code = NULL;
03911
03912 if (ast_strlen_zero(name)) {
03913 astman_send_error(s, m, "No channel specified");
03914 return 0;
03915 }
03916 if (ast_strlen_zero(exten)) {
03917 astman_send_error(s, m, "No extension specified");
03918 return 0;
03919 }
03920
03921 if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
03922 astman_send_error(s, m, "No attended transfer feature found");
03923 return 0;
03924 }
03925
03926 if (!(chan = ast_channel_get_by_name(name))) {
03927 astman_send_error(s, m, "Channel specified does not exist");
03928 return 0;
03929 }
03930
03931 if (!ast_strlen_zero(context)) {
03932 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
03933 }
03934
03935 for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
03936 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
03937 ast_queue_frame(chan, &f);
03938 }
03939
03940 for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
03941 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
03942 ast_queue_frame(chan, &f);
03943 }
03944
03945 chan = ast_channel_unref(chan);
03946
03947 astman_send_ack(s, m, "Atxfer successfully queued");
03948
03949 return 0;
03950 }
03951
03952 static int check_blacklist(const char *cmd)
03953 {
03954 char *cmd_copy, *cur_cmd;
03955 char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
03956 int i;
03957
03958 cmd_copy = ast_strdupa(cmd);
03959 for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
03960 cur_cmd = ast_strip(cur_cmd);
03961 if (ast_strlen_zero(cur_cmd)) {
03962 i--;
03963 continue;
03964 }
03965
03966 cmd_words[i] = cur_cmd;
03967 }
03968
03969 for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
03970 int j, match = 1;
03971
03972 for (j = 0; command_blacklist[i].words[j]; j++) {
03973 if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
03974 match = 0;
03975 break;
03976 }
03977 }
03978
03979 if (match) {
03980 return 1;
03981 }
03982 }
03983
03984 return 0;
03985 }
03986
03987
03988 static int action_command(struct mansession *s, const struct message *m)
03989 {
03990 const char *cmd = astman_get_header(m, "Command");
03991 const char *id = astman_get_header(m, "ActionID");
03992 char *buf = NULL, *final_buf = NULL;
03993 char template[] = "/tmp/ast-ami-XXXXXX";
03994 int fd;
03995 off_t l;
03996
03997 if (ast_strlen_zero(cmd)) {
03998 astman_send_error(s, m, "No command provided");
03999 return 0;
04000 }
04001
04002 if (check_blacklist(cmd)) {
04003 astman_send_error(s, m, "Command blacklisted");
04004 return 0;
04005 }
04006
04007 if ((fd = mkstemp(template)) < 0) {
04008 ast_log(AST_LOG_WARNING, "Failed to create temporary file for command: %s\n", strerror(errno));
04009 astman_send_error(s, m, "Command response construction error");
04010 return 0;
04011 }
04012
04013 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
04014 if (!ast_strlen_zero(id)) {
04015 astman_append(s, "ActionID: %s\r\n", id);
04016 }
04017
04018 ast_cli_command(fd, cmd);
04019
04020 if ((l = lseek(fd, 0, SEEK_END)) < 0) {
04021 ast_log(LOG_WARNING, "Failed to determine number of characters for command: %s\n", strerror(errno));
04022 goto action_command_cleanup;
04023 }
04024
04025
04026 buf = ast_malloc(l + 1);
04027 final_buf = ast_malloc(l + 1);
04028
04029 if (!buf || !final_buf) {
04030 ast_log(LOG_WARNING, "Failed to allocate memory for temporary buffer\n");
04031 goto action_command_cleanup;
04032 }
04033
04034 if (lseek(fd, 0, SEEK_SET) < 0) {
04035 ast_log(LOG_WARNING, "Failed to set position on temporary file for command: %s\n", strerror(errno));
04036 goto action_command_cleanup;
04037 }
04038
04039 if (read(fd, buf, l) < 0) {
04040 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
04041 goto action_command_cleanup;
04042 }
04043
04044 buf[l] = '\0';
04045 term_strip(final_buf, buf, l);
04046 final_buf[l] = '\0';
04047 astman_append(s, "%s", final_buf);
04048
04049 action_command_cleanup:
04050
04051 close(fd);
04052 unlink(template);
04053 astman_append(s, "--END COMMAND--\r\n\r\n");
04054
04055 ast_free(buf);
04056 ast_free(final_buf);
04057
04058 return 0;
04059 }
04060
04061
04062 struct fast_originate_helper {
04063 int timeout;
04064 struct ast_format_cap *cap;
04065 int early_media;
04066 AST_DECLARE_STRING_FIELDS (
04067 AST_STRING_FIELD(tech);
04068
04069 AST_STRING_FIELD(data);
04070 AST_STRING_FIELD(app);
04071 AST_STRING_FIELD(appdata);
04072 AST_STRING_FIELD(cid_name);
04073 AST_STRING_FIELD(cid_num);
04074 AST_STRING_FIELD(context);
04075 AST_STRING_FIELD(exten);
04076 AST_STRING_FIELD(idtext);
04077 AST_STRING_FIELD(account);
04078 );
04079 int priority;
04080 struct ast_variable *vars;
04081 };
04082
04083
04084
04085
04086
04087
04088
04089
04090 static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
04091 {
04092 ast_format_cap_destroy(doomed->cap);
04093 ast_variables_destroy(doomed->vars);
04094 ast_string_field_free_memory(doomed);
04095 ast_free(doomed);
04096 }
04097
04098 static void *fast_originate(void *data)
04099 {
04100 struct fast_originate_helper *in = data;
04101 int res;
04102 int reason = 0;
04103 struct ast_channel *chan = NULL, *chans[1];
04104 char requested_channel[AST_CHANNEL_NAME];
04105
04106 if (!ast_strlen_zero(in->app)) {
04107 res = ast_pbx_outgoing_app(in->tech, in->cap, in->data,
04108 in->timeout, in->app, in->appdata, &reason, 1,
04109 S_OR(in->cid_num, NULL),
04110 S_OR(in->cid_name, NULL),
04111 in->vars, in->account, &chan);
04112 } else {
04113 res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data,
04114 in->timeout, in->context, in->exten, in->priority, &reason, 1,
04115 S_OR(in->cid_num, NULL),
04116 S_OR(in->cid_name, NULL),
04117 in->vars, in->account, &chan, in->early_media);
04118 }
04119
04120 in->vars = NULL;
04121
04122 if (!chan) {
04123 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
04124 }
04125
04126 chans[0] = chan;
04127 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
04128 "%s"
04129 "Response: %s\r\n"
04130 "Channel: %s\r\n"
04131 "Context: %s\r\n"
04132 "Exten: %s\r\n"
04133 "Reason: %d\r\n"
04134 "Uniqueid: %s\r\n"
04135 "CallerIDNum: %s\r\n"
04136 "CallerIDName: %s\r\n",
04137 in->idtext, res ? "Failure" : "Success",
04138 chan ? ast_channel_name(chan) : requested_channel, in->context, in->exten, reason,
04139 chan ? ast_channel_uniqueid(chan) : "<null>",
04140 S_OR(in->cid_num, "<unknown>"),
04141 S_OR(in->cid_name, "<unknown>")
04142 );
04143
04144
04145 if (chan) {
04146 ast_channel_unlock(chan);
04147 }
04148 destroy_fast_originate_helper(in);
04149 return NULL;
04150 }
04151
04152 static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
04153 {
04154 const char *unitamount;
04155 const char *unittype;
04156 struct ast_str *str = ast_str_alloca(32);
04157
04158 memset(entry, 0, sizeof(*entry));
04159
04160 ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
04161 unitamount = astman_get_header(m, ast_str_buffer(str));
04162
04163 ast_str_set(&str, 0, "UnitType(%u)", entry_num);
04164 unittype = astman_get_header(m, ast_str_buffer(str));
04165
04166 if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
04167 entry->valid_amount = 1;
04168 }
04169
04170 if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
04171 entry->valid_type = 1;
04172 }
04173
04174 return 0;
04175 }
04176
04177 static int action_aocmessage(struct mansession *s, const struct message *m)
04178 {
04179 const char *channel = astman_get_header(m, "Channel");
04180 const char *pchannel = astman_get_header(m, "ChannelPrefix");
04181 const char *msgtype = astman_get_header(m, "MsgType");
04182 const char *chargetype = astman_get_header(m, "ChargeType");
04183 const char *currencyname = astman_get_header(m, "CurrencyName");
04184 const char *currencyamount = astman_get_header(m, "CurrencyAmount");
04185 const char *mult = astman_get_header(m, "CurrencyMultiplier");
04186 const char *totaltype = astman_get_header(m, "TotalType");
04187 const char *aocbillingid = astman_get_header(m, "AOCBillingId");
04188 const char *association_id= astman_get_header(m, "ChargingAssociationId");
04189 const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
04190 const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
04191
04192 enum ast_aoc_type _msgtype;
04193 enum ast_aoc_charge_type _chargetype;
04194 enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
04195 enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
04196 enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
04197 unsigned int _currencyamount = 0;
04198 int _association_id = 0;
04199 unsigned int _association_plan = 0;
04200 struct ast_channel *chan = NULL;
04201
04202 struct ast_aoc_decoded *decoded = NULL;
04203 struct ast_aoc_encoded *encoded = NULL;
04204 size_t encoded_size = 0;
04205
04206 if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
04207 astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
04208 goto aocmessage_cleanup;
04209 }
04210
04211 if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
04212 chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
04213 }
04214
04215 if (!chan) {
04216 astman_send_error(s, m, "No such channel");
04217 goto aocmessage_cleanup;
04218 }
04219
04220 if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
04221 astman_send_error(s, m, "Invalid MsgType");
04222 goto aocmessage_cleanup;
04223 }
04224
04225 if (ast_strlen_zero(chargetype)) {
04226 astman_send_error(s, m, "ChargeType not specified");
04227 goto aocmessage_cleanup;
04228 }
04229
04230 _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
04231
04232 if (!strcasecmp(chargetype, "NA")) {
04233 _chargetype = AST_AOC_CHARGE_NA;
04234 } else if (!strcasecmp(chargetype, "Free")) {
04235 _chargetype = AST_AOC_CHARGE_FREE;
04236 } else if (!strcasecmp(chargetype, "Currency")) {
04237 _chargetype = AST_AOC_CHARGE_CURRENCY;
04238 } else if (!strcasecmp(chargetype, "Unit")) {
04239 _chargetype = AST_AOC_CHARGE_UNIT;
04240 } else {
04241 astman_send_error(s, m, "Invalid ChargeType");
04242 goto aocmessage_cleanup;
04243 }
04244
04245 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
04246
04247 if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
04248 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
04249 goto aocmessage_cleanup;
04250 }
04251
04252 if (ast_strlen_zero(mult)) {
04253 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
04254 goto aocmessage_cleanup;
04255 } else if (!strcasecmp(mult, "onethousandth")) {
04256 _mult = AST_AOC_MULT_ONETHOUSANDTH;
04257 } else if (!strcasecmp(mult, "onehundredth")) {
04258 _mult = AST_AOC_MULT_ONEHUNDREDTH;
04259 } else if (!strcasecmp(mult, "onetenth")) {
04260 _mult = AST_AOC_MULT_ONETENTH;
04261 } else if (!strcasecmp(mult, "one")) {
04262 _mult = AST_AOC_MULT_ONE;
04263 } else if (!strcasecmp(mult, "ten")) {
04264 _mult = AST_AOC_MULT_TEN;
04265 } else if (!strcasecmp(mult, "hundred")) {
04266 _mult = AST_AOC_MULT_HUNDRED;
04267 } else if (!strcasecmp(mult, "thousand")) {
04268 _mult = AST_AOC_MULT_THOUSAND;
04269 } else {
04270 astman_send_error(s, m, "Invalid ChargeMultiplier");
04271 goto aocmessage_cleanup;
04272 }
04273 }
04274
04275
04276 if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
04277 astman_send_error(s, m, "Message Creation Failed");
04278 goto aocmessage_cleanup;
04279 }
04280
04281 if (_msgtype == AST_AOC_D) {
04282 if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
04283 _totaltype = AST_AOC_SUBTOTAL;
04284 }
04285
04286 if (ast_strlen_zero(aocbillingid)) {
04287
04288 } else if (!strcasecmp(aocbillingid, "Normal")) {
04289 _billingid = AST_AOC_BILLING_NORMAL;
04290 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
04291 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
04292 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
04293 _billingid = AST_AOC_BILLING_CREDIT_CARD;
04294 } else {
04295 astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
04296 goto aocmessage_cleanup;
04297 }
04298 } else {
04299 if (ast_strlen_zero(aocbillingid)) {
04300
04301 } else if (!strcasecmp(aocbillingid, "Normal")) {
04302 _billingid = AST_AOC_BILLING_NORMAL;
04303 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
04304 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
04305 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
04306 _billingid = AST_AOC_BILLING_CREDIT_CARD;
04307 } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
04308 _billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL;
04309 } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
04310 _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
04311 } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
04312 _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
04313 } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
04314 _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
04315 } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
04316 _billingid = AST_AOC_BILLING_CALL_TRANSFER;
04317 } else {
04318 astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
04319 goto aocmessage_cleanup;
04320 }
04321
04322 if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
04323 astman_send_error(s, m, "Invalid ChargingAssociationId");
04324 goto aocmessage_cleanup;
04325 }
04326 if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
04327 astman_send_error(s, m, "Invalid ChargingAssociationPlan");
04328 goto aocmessage_cleanup;
04329 }
04330
04331 if (_association_id) {
04332 ast_aoc_set_association_id(decoded, _association_id);
04333 } else if (!ast_strlen_zero(association_num)) {
04334 ast_aoc_set_association_number(decoded, association_num, _association_plan);
04335 }
04336 }
04337
04338 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
04339 ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
04340 } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
04341 struct ast_aoc_unit_entry entry;
04342 int i;
04343
04344
04345 for (i = 0; i < 32; i++) {
04346 if (aocmessage_get_unit_entry(m, &entry, i)) {
04347 break;
04348 }
04349
04350 ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
04351 }
04352
04353
04354 if (!i) {
04355 astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
04356 goto aocmessage_cleanup;
04357 }
04358
04359 }
04360
04361 ast_aoc_set_billing_id(decoded, _billingid);
04362 ast_aoc_set_total_type(decoded, _totaltype);
04363
04364
04365 if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
04366 astman_send_ack(s, m, "AOC Message successfully queued on channel");
04367 } else {
04368 astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
04369 }
04370
04371 aocmessage_cleanup:
04372
04373 ast_aoc_destroy_decoded(decoded);
04374 ast_aoc_destroy_encoded(encoded);
04375
04376 if (chan) {
04377 chan = ast_channel_unref(chan);
04378 }
04379 return 0;
04380 }
04381
04382 static int action_originate(struct mansession *s, const struct message *m)
04383 {
04384 const char *name = astman_get_header(m, "Channel");
04385 const char *exten = astman_get_header(m, "Exten");
04386 const char *context = astman_get_header(m, "Context");
04387 const char *priority = astman_get_header(m, "Priority");
04388 const char *timeout = astman_get_header(m, "Timeout");
04389 const char *callerid = astman_get_header(m, "CallerID");
04390 const char *account = astman_get_header(m, "Account");
04391 const char *app = astman_get_header(m, "Application");
04392 const char *appdata = astman_get_header(m, "Data");
04393 const char *async = astman_get_header(m, "Async");
04394 const char *id = astman_get_header(m, "ActionID");
04395 const char *codecs = astman_get_header(m, "Codecs");
04396 const char *early_media = astman_get_header(m, "Earlymedia");
04397 struct ast_variable *vars = NULL;
04398 char *tech, *data;
04399 char *l = NULL, *n = NULL;
04400 int pi = 0;
04401 int res;
04402 int to = 30000;
04403 int reason = 0;
04404 char tmp[256];
04405 char tmp2[256];
04406 struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
04407 struct ast_format tmp_fmt;
04408 pthread_t th;
04409 int bridge_early = 0;
04410
04411 if (!cap) {
04412 astman_send_error(s, m, "Internal Error. Memory allocation failure.");
04413 return 0;
04414 }
04415 ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
04416
04417 if (ast_strlen_zero(name)) {
04418 astman_send_error(s, m, "Channel not specified");
04419 res = 0;
04420 goto fast_orig_cleanup;
04421 }
04422 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
04423 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
04424 astman_send_error(s, m, "Invalid priority");
04425 res = 0;
04426 goto fast_orig_cleanup;
04427 }
04428 }
04429 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
04430 astman_send_error(s, m, "Invalid timeout");
04431 res = 0;
04432 goto fast_orig_cleanup;
04433 }
04434 ast_copy_string(tmp, name, sizeof(tmp));
04435 tech = tmp;
04436 data = strchr(tmp, '/');
04437 if (!data) {
04438 astman_send_error(s, m, "Invalid channel");
04439 res = 0;
04440 goto fast_orig_cleanup;
04441 }
04442 *data++ = '\0';
04443 ast_copy_string(tmp2, callerid, sizeof(tmp2));
04444 ast_callerid_parse(tmp2, &n, &l);
04445 if (n) {
04446 if (ast_strlen_zero(n)) {
04447 n = NULL;
04448 }
04449 }
04450 if (l) {
04451 ast_shrink_phone_number(l);
04452 if (ast_strlen_zero(l)) {
04453 l = NULL;
04454 }
04455 }
04456 if (!ast_strlen_zero(codecs)) {
04457 ast_format_cap_remove_all(cap);
04458 ast_parse_allow_disallow(NULL, cap, codecs, 1);
04459 }
04460
04461 if (!ast_strlen_zero(app) && s->session) {
04462 int bad_appdata = 0;
04463
04464
04465 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
04466 && (
04467 strcasestr(app, "system") ||
04468
04469 strcasestr(app, "exec") ||
04470
04471 strcasestr(app, "agi") ||
04472
04473 strcasestr(app, "mixmonitor") ||
04474 strcasestr(app, "externalivr") ||
04475 (strstr(appdata, "SHELL") && (bad_appdata = 1)) ||
04476 (strstr(appdata, "EVAL") && (bad_appdata = 1))
04477 )) {
04478 char error_buf[64];
04479 snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
04480 astman_send_error(s, m, error_buf);
04481 res = 0;
04482 goto fast_orig_cleanup;
04483 }
04484 }
04485
04486
04487 if (exten && context && pi) {
04488 if (! ast_exists_extension(NULL, context, exten, pi, l)) {
04489
04490 astman_send_error(s, m, "Extension does not exist.");
04491 res = 0;
04492 goto fast_orig_cleanup;
04493 }
04494 }
04495
04496
04497 vars = astman_get_variables(m);
04498 if (s->session && s->session->chanvars) {
04499 struct ast_variable *v, *old;
04500 old = vars;
04501 vars = NULL;
04502
04503
04504
04505 vars = ast_variables_dup(s->session->chanvars);
04506 if (old) {
04507 for (v = vars; v->next; v = v->next );
04508 if (v->next) {
04509 v->next = old;
04510 }
04511 }
04512 }
04513
04514
04515 bridge_early = ast_true(early_media);
04516
04517 if (ast_true(async)) {
04518 struct fast_originate_helper *fast;
04519
04520 fast = ast_calloc(1, sizeof(*fast));
04521 if (!fast || ast_string_field_init(fast, 252)) {
04522 ast_free(fast);
04523 ast_variables_destroy(vars);
04524 res = -1;
04525 } else {
04526 if (!ast_strlen_zero(id)) {
04527 ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id);
04528 }
04529 ast_string_field_set(fast, tech, tech);
04530 ast_string_field_set(fast, data, data);
04531 ast_string_field_set(fast, app, app);
04532 ast_string_field_set(fast, appdata, appdata);
04533 ast_string_field_set(fast, cid_num, l);
04534 ast_string_field_set(fast, cid_name, n);
04535 ast_string_field_set(fast, context, context);
04536 ast_string_field_set(fast, exten, exten);
04537 ast_string_field_set(fast, account, account);
04538 fast->vars = vars;
04539 fast->cap = cap;
04540 cap = NULL;
04541 fast->timeout = to;
04542 fast->early_media = bridge_early;
04543 fast->priority = pi;
04544 if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
04545 destroy_fast_originate_helper(fast);
04546 res = -1;
04547 } else {
04548 res = 0;
04549 }
04550 }
04551 } else if (!ast_strlen_zero(app)) {
04552 res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
04553
04554 } else {
04555 if (exten && context && pi) {
04556 res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL, bridge_early);
04557
04558 } else {
04559 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
04560 ast_variables_destroy(vars);
04561 res = 0;
04562 goto fast_orig_cleanup;
04563 }
04564 }
04565 if (!res) {
04566 astman_send_ack(s, m, "Originate successfully queued");
04567 } else {
04568 astman_send_error(s, m, "Originate failed");
04569 }
04570
04571 fast_orig_cleanup:
04572 ast_format_cap_destroy(cap);
04573 return 0;
04574 }
04575
04576 static int action_mailboxstatus(struct mansession *s, const struct message *m)
04577 {
04578 const char *mailbox = astman_get_header(m, "Mailbox");
04579 int ret;
04580
04581 if (ast_strlen_zero(mailbox)) {
04582 astman_send_error(s, m, "Mailbox not specified");
04583 return 0;
04584 }
04585 ret = ast_app_has_voicemail(mailbox, NULL);
04586 astman_start_ack(s, m);
04587 astman_append(s, "Message: Mailbox Status\r\n"
04588 "Mailbox: %s\r\n"
04589 "Waiting: %d\r\n\r\n", mailbox, ret);
04590 return 0;
04591 }
04592
04593 static int action_mailboxcount(struct mansession *s, const struct message *m)
04594 {
04595 const char *mailbox = astman_get_header(m, "Mailbox");
04596 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
04597
04598 if (ast_strlen_zero(mailbox)) {
04599 astman_send_error(s, m, "Mailbox not specified");
04600 return 0;
04601 }
04602 ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
04603 astman_start_ack(s, m);
04604 astman_append(s, "Message: Mailbox Message Count\r\n"
04605 "Mailbox: %s\r\n"
04606 "UrgMessages: %d\r\n"
04607 "NewMessages: %d\r\n"
04608 "OldMessages: %d\r\n"
04609 "\r\n",
04610 mailbox, urgentmsgs, newmsgs, oldmsgs);
04611 return 0;
04612 }
04613
04614 static int action_extensionstate(struct mansession *s, const struct message *m)
04615 {
04616 const char *exten = astman_get_header(m, "Exten");
04617 const char *context = astman_get_header(m, "Context");
04618 char hint[256] = "";
04619 int status;
04620 if (ast_strlen_zero(exten)) {
04621 astman_send_error(s, m, "Extension not specified");
04622 return 0;
04623 }
04624 if (ast_strlen_zero(context)) {
04625 context = "default";
04626 }
04627 status = ast_extension_state(NULL, context, exten);
04628 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
04629 astman_start_ack(s, m);
04630 astman_append(s, "Message: Extension Status\r\n"
04631 "Exten: %s\r\n"
04632 "Context: %s\r\n"
04633 "Hint: %s\r\n"
04634 "Status: %d\r\n\r\n",
04635 exten, context, hint, status);
04636 return 0;
04637 }
04638
04639 static int action_presencestate(struct mansession *s, const struct message *m)
04640 {
04641 const char *provider = astman_get_header(m, "Provider");
04642 enum ast_presence_state state;
04643 char *subtype;
04644 char *message;
04645 char subtype_header[256] = "";
04646 char message_header[256] = "";
04647
04648 if (ast_strlen_zero(provider)) {
04649 astman_send_error(s, m, "No provider specified");
04650 return 0;
04651 }
04652
04653 state = ast_presence_state(provider, &subtype, &message);
04654 if (state == AST_PRESENCE_INVALID) {
04655 astman_send_error_va(s, m, "Invalid provider %s or provider in invalid state", provider);
04656 return 0;
04657 }
04658
04659 if (!ast_strlen_zero(subtype)) {
04660 snprintf(subtype_header, sizeof(subtype_header),
04661 "Subtype: %s\r\n", subtype);
04662 }
04663
04664 if (!ast_strlen_zero(message)) {
04665 snprintf(message_header, sizeof(message_header),
04666 "Message: %s\r\n", message);
04667 }
04668
04669 astman_append(s, "Message: Presence State\r\n"
04670 "State: %s\r\n"
04671 "%s"
04672 "%s"
04673 "\r\n",
04674 ast_presence_state2str(state),
04675 subtype_header,
04676 message_header);
04677 return 0;
04678 }
04679
04680 static int action_timeout(struct mansession *s, const struct message *m)
04681 {
04682 struct ast_channel *c;
04683 const char *name = astman_get_header(m, "Channel");
04684 double timeout = atof(astman_get_header(m, "Timeout"));
04685 struct timeval when = { timeout, 0 };
04686
04687 if (ast_strlen_zero(name)) {
04688 astman_send_error(s, m, "No channel specified");
04689 return 0;
04690 }
04691
04692 if (!timeout || timeout < 0) {
04693 astman_send_error(s, m, "No timeout specified");
04694 return 0;
04695 }
04696
04697 if (!(c = ast_channel_get_by_name(name))) {
04698 astman_send_error(s, m, "No such channel");
04699 return 0;
04700 }
04701
04702 when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
04703
04704 ast_channel_lock(c);
04705 ast_channel_setwhentohangup_tv(c, when);
04706 ast_channel_unlock(c);
04707 c = ast_channel_unref(c);
04708
04709 astman_send_ack(s, m, "Timeout Set");
04710
04711 return 0;
04712 }
04713
04714 static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04715 {
04716 regex_t *regex_filter = obj;
04717 const char *eventdata = arg;
04718 int *result = data;
04719
04720 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
04721 *result = 1;
04722 return (CMP_MATCH | CMP_STOP);
04723 }
04724
04725 return 0;
04726 }
04727
04728 static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04729 {
04730 regex_t *regex_filter = obj;
04731 const char *eventdata = arg;
04732 int *result = data;
04733
04734 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
04735 *result = 0;
04736 return (CMP_MATCH | CMP_STOP);
04737 }
04738
04739 *result = 1;
04740 return 0;
04741 }
04742
04743
04744
04745
04746
04747 static int action_filter(struct mansession *s, const struct message *m)
04748 {
04749 const char *filter = astman_get_header(m, "Filter");
04750 const char *operation = astman_get_header(m, "Operation");
04751 int res;
04752
04753 if (!strcasecmp(operation, "Add")) {
04754 res = manager_add_filter(filter, s->session->whitefilters, s->session->blackfilters);
04755
04756 if (res != FILTER_SUCCESS) {
04757 if (res == FILTER_ALLOC_FAILED) {
04758 astman_send_error(s, m, "Internal Error. Failed to allocate regex for filter");
04759 return 0;
04760 } else if (res == FILTER_COMPILE_FAIL) {
04761 astman_send_error(s, m, "Filter did not compile. Check the syntax of the filter given.");
04762 return 0;
04763 } else {
04764 astman_send_error(s, m, "Internal Error. Failed adding filter.");
04765 return 0;
04766 }
04767 }
04768
04769 astman_send_ack(s, m, "Success");
04770 return 0;
04771 }
04772
04773 astman_send_error(s, m, "Unknown operation");
04774 return 0;
04775 }
04776
04777
04778
04779
04780
04781
04782
04783
04784
04785
04786
04787
04788
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters) {
04799 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
04800 int is_blackfilter;
04801
04802 if (!new_filter) {
04803 return FILTER_ALLOC_FAILED;
04804 }
04805
04806 if (filter_pattern[0] == '!') {
04807 is_blackfilter = 1;
04808 filter_pattern++;
04809 } else {
04810 is_blackfilter = 0;
04811 }
04812
04813 if (regcomp(new_filter, filter_pattern, 0)) {
04814 ao2_t_ref(new_filter, -1, "failed to make regex");
04815 return FILTER_COMPILE_FAIL;
04816 }
04817
04818 if (is_blackfilter) {
04819 ao2_t_link(blackfilters, new_filter, "link new filter into black user container");
04820 } else {
04821 ao2_t_link(whitefilters, new_filter, "link new filter into white user container");
04822 }
04823
04824 ao2_ref(new_filter, -1);
04825
04826 return FILTER_SUCCESS;
04827 }
04828
04829 static int match_filter(struct mansession *s, char *eventdata)
04830 {
04831 int result = 0;
04832
04833 ast_debug(3, "Examining event:\n%s\n", eventdata);
04834 if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04835 return 1;
04836 } else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04837
04838 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04839 } else if (!ao2_container_count(s->session->whitefilters) && ao2_container_count(s->session->blackfilters)) {
04840
04841 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04842 } else {
04843
04844 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04845 if (result) {
04846 result = 0;
04847 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04848 }
04849 }
04850
04851 return result;
04852 }
04853
04854
04855
04856
04857
04858
04859 static int process_events(struct mansession *s)
04860 {
04861 int ret = 0;
04862
04863 ao2_lock(s->session);
04864 if (s->session->f != NULL) {
04865 struct eventqent *eqe = s->session->last_ev;
04866
04867 while ((eqe = advance_event(eqe))) {
04868 if (!ret && s->session->authenticated &&
04869 (s->session->readperm & eqe->category) == eqe->category &&
04870 (s->session->send_events & eqe->category) == eqe->category) {
04871 if (match_filter(s, eqe->eventdata)) {
04872 if (send_string(s, eqe->eventdata) < 0)
04873 ret = -1;
04874 }
04875 }
04876 s->session->last_ev = eqe;
04877 }
04878 }
04879 ao2_unlock(s->session);
04880 return ret;
04881 }
04882
04883 static int action_userevent(struct mansession *s, const struct message *m)
04884 {
04885 const char *event = astman_get_header(m, "UserEvent");
04886 struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
04887 int x;
04888
04889 ast_str_reset(body);
04890
04891 for (x = 0; x < m->hdrcount; x++) {
04892 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
04893 ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
04894 }
04895 }
04896
04897 astman_send_ack(s, m, "Event Sent");
04898 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
04899 return 0;
04900 }
04901
04902
04903 static int action_coresettings(struct mansession *s, const struct message *m)
04904 {
04905 const char *actionid = astman_get_header(m, "ActionID");
04906 char idText[150];
04907
04908 if (!ast_strlen_zero(actionid)) {
04909 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04910 } else {
04911 idText[0] = '\0';
04912 }
04913
04914 astman_append(s, "Response: Success\r\n"
04915 "%s"
04916 "AMIversion: %s\r\n"
04917 "AsteriskVersion: %s\r\n"
04918 "SystemName: %s\r\n"
04919 "CoreMaxCalls: %d\r\n"
04920 "CoreMaxLoadAvg: %f\r\n"
04921 "CoreRunUser: %s\r\n"
04922 "CoreRunGroup: %s\r\n"
04923 "CoreMaxFilehandles: %d\r\n"
04924 "CoreRealTimeEnabled: %s\r\n"
04925 "CoreCDRenabled: %s\r\n"
04926 "CoreHTTPenabled: %s\r\n"
04927 "\r\n",
04928 idText,
04929 AMI_VERSION,
04930 ast_get_version(),
04931 ast_config_AST_SYSTEM_NAME,
04932 option_maxcalls,
04933 option_maxload,
04934 ast_config_AST_RUN_USER,
04935 ast_config_AST_RUN_GROUP,
04936 option_maxfiles,
04937 AST_CLI_YESNO(ast_realtime_enabled()),
04938 AST_CLI_YESNO(check_cdr_enabled()),
04939 AST_CLI_YESNO(check_webmanager_enabled())
04940 );
04941 return 0;
04942 }
04943
04944
04945 static int action_corestatus(struct mansession *s, const struct message *m)
04946 {
04947 const char *actionid = astman_get_header(m, "ActionID");
04948 char idText[150];
04949 char startuptime[150], startupdate[150];
04950 char reloadtime[150], reloaddate[150];
04951 struct ast_tm tm;
04952
04953 if (!ast_strlen_zero(actionid)) {
04954 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04955 } else {
04956 idText[0] = '\0';
04957 }
04958
04959 ast_localtime(&ast_startuptime, &tm, NULL);
04960 ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
04961 ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
04962 ast_localtime(&ast_lastreloadtime, &tm, NULL);
04963 ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
04964 ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
04965
04966 astman_append(s, "Response: Success\r\n"
04967 "%s"
04968 "CoreStartupDate: %s\r\n"
04969 "CoreStartupTime: %s\r\n"
04970 "CoreReloadDate: %s\r\n"
04971 "CoreReloadTime: %s\r\n"
04972 "CoreCurrentCalls: %d\r\n"
04973 "\r\n",
04974 idText,
04975 startupdate,
04976 startuptime,
04977 reloaddate,
04978 reloadtime,
04979 ast_active_channels()
04980 );
04981 return 0;
04982 }
04983
04984
04985 static int action_reload(struct mansession *s, const struct message *m)
04986 {
04987 const char *module = astman_get_header(m, "Module");
04988 int res = ast_module_reload(S_OR(module, NULL));
04989
04990 switch (res) {
04991 case -1:
04992 astman_send_error(s, m, "A reload is in progress");
04993 break;
04994 case 0:
04995 astman_send_error(s, m, "No such module");
04996 break;
04997 case 1:
04998 astman_send_error(s, m, "Module does not support reload");
04999 break;
05000 case 2:
05001 astman_send_ack(s, m, "Module Reloaded");
05002 break;
05003 default:
05004 astman_send_error(s, m, "An unknown error occurred");
05005 break;
05006 }
05007 return 0;
05008 }
05009
05010
05011
05012 static int action_coreshowchannels(struct mansession *s, const struct message *m)
05013 {
05014 const char *actionid = astman_get_header(m, "ActionID");
05015 char idText[256];
05016 struct ast_channel *c = NULL;
05017 int numchans = 0;
05018 int duration, durh, durm, durs;
05019 struct ast_channel_iterator *iter;
05020
05021 if (!ast_strlen_zero(actionid)) {
05022 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
05023 } else {
05024 idText[0] = '\0';
05025 }
05026
05027 if (!(iter = ast_channel_iterator_all_new())) {
05028 astman_send_error(s, m, "Memory Allocation Failure");
05029 return 1;
05030 }
05031
05032 astman_send_listack(s, m, "Channels will follow", "start");
05033
05034 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
05035 struct ast_channel *bc;
05036 char durbuf[10] = "";
05037
05038 ast_channel_lock(c);
05039
05040 bc = ast_bridged_channel(c);
05041 if (ast_channel_cdr(c) && !ast_tvzero(ast_channel_cdr(c)->start)) {
05042 duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_cdr(c)->start) / 1000);
05043 durh = duration / 3600;
05044 durm = (duration % 3600) / 60;
05045 durs = duration % 60;
05046 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
05047 }
05048
05049 astman_append(s,
05050 "Event: CoreShowChannel\r\n"
05051 "%s"
05052 "Channel: %s\r\n"
05053 "UniqueID: %s\r\n"
05054 "Context: %s\r\n"
05055 "Extension: %s\r\n"
05056 "Priority: %d\r\n"
05057 "ChannelState: %u\r\n"
05058 "ChannelStateDesc: %s\r\n"
05059 "Application: %s\r\n"
05060 "ApplicationData: %s\r\n"
05061 "CallerIDnum: %s\r\n"
05062 "CallerIDname: %s\r\n"
05063 "ConnectedLineNum: %s\r\n"
05064 "ConnectedLineName: %s\r\n"
05065 "Duration: %s\r\n"
05066 "AccountCode: %s\r\n"
05067 "BridgedChannel: %s\r\n"
05068 "BridgedUniqueID: %s\r\n"
05069 "\r\n", idText, ast_channel_name(c), ast_channel_uniqueid(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_state(c),
05070 ast_state2str(ast_channel_state(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "", ast_channel_data(c) ? S_OR(ast_channel_data(c), "") : "",
05071 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
05072 S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
05073 S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, ""),
05074 S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, ""),
05075 durbuf, S_OR(ast_channel_accountcode(c), ""), bc ? ast_channel_name(bc) : "", bc ? ast_channel_uniqueid(bc) : "");
05076
05077 ast_channel_unlock(c);
05078
05079 numchans++;
05080 }
05081
05082 astman_append(s,
05083 "Event: CoreShowChannelsComplete\r\n"
05084 "EventList: Complete\r\n"
05085 "ListItems: %d\r\n"
05086 "%s"
05087 "\r\n", numchans, idText);
05088
05089 ast_channel_iterator_destroy(iter);
05090
05091 return 0;
05092 }
05093
05094
05095 static int manager_modulecheck(struct mansession *s, const struct message *m)
05096 {
05097 int res;
05098 const char *module = astman_get_header(m, "Module");
05099 const char *id = astman_get_header(m, "ActionID");
05100 char idText[256];
05101 #if !defined(LOW_MEMORY)
05102 const char *version;
05103 #endif
05104 char filename[PATH_MAX];
05105 char *cut;
05106
05107 ast_copy_string(filename, module, sizeof(filename));
05108 if ((cut = strchr(filename, '.'))) {
05109 *cut = '\0';
05110 } else {
05111 cut = filename + strlen(filename);
05112 }
05113 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
05114 ast_debug(1, "**** ModuleCheck .so file %s\n", filename);
05115 res = ast_module_check(filename);
05116 if (!res) {
05117 astman_send_error(s, m, "Module not loaded");
05118 return 0;
05119 }
05120 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
05121 ast_debug(1, "**** ModuleCheck .c file %s\n", filename);
05122 #if !defined(LOW_MEMORY)
05123 version = ast_file_version_find(filename);
05124 #endif
05125
05126 if (!ast_strlen_zero(id)) {
05127 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05128 } else {
05129 idText[0] = '\0';
05130 }
05131 astman_append(s, "Response: Success\r\n%s", idText);
05132 #if !defined(LOW_MEMORY)
05133 astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
05134 #endif
05135 return 0;
05136 }
05137
05138 static int manager_moduleload(struct mansession *s, const struct message *m)
05139 {
05140 int res;
05141 const char *module = astman_get_header(m, "Module");
05142 const char *loadtype = astman_get_header(m, "LoadType");
05143
05144 if (!loadtype || strlen(loadtype) == 0) {
05145 astman_send_error(s, m, "Incomplete ModuleLoad action.");
05146 }
05147 if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
05148 astman_send_error(s, m, "Need module name");
05149 }
05150
05151 if (!strcasecmp(loadtype, "load")) {
05152 res = ast_load_resource(module);
05153 if (res) {
05154 astman_send_error(s, m, "Could not load module.");
05155 } else {
05156 astman_send_ack(s, m, "Module loaded.");
05157 }
05158 } else if (!strcasecmp(loadtype, "unload")) {
05159 res = ast_unload_resource(module, AST_FORCE_SOFT);
05160 if (res) {
05161 astman_send_error(s, m, "Could not unload module.");
05162 } else {
05163 astman_send_ack(s, m, "Module unloaded.");
05164 }
05165 } else if (!strcasecmp(loadtype, "reload")) {
05166 if (!ast_strlen_zero(module)) {
05167 res = ast_module_reload(module);
05168 if (res == 0) {
05169 astman_send_error(s, m, "No such module.");
05170 } else if (res == 1) {
05171 astman_send_error(s, m, "Module does not support reload action.");
05172 } else {
05173 astman_send_ack(s, m, "Module reloaded.");
05174 }
05175 } else {
05176 ast_module_reload(NULL);
05177 astman_send_ack(s, m, "All modules reloaded");
05178 }
05179 } else
05180 astman_send_error(s, m, "Incomplete ModuleLoad action.");
05181 return 0;
05182 }
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192
05193
05194
05195
05196
05197 static int process_message(struct mansession *s, const struct message *m)
05198 {
05199 int ret = 0;
05200 struct manager_action *act_found;
05201 const char *user;
05202 const char *action;
05203
05204 action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
05205 if (ast_strlen_zero(action)) {
05206 report_req_bad_format(s, "NONE");
05207 mansession_lock(s);
05208 astman_send_error(s, m, "Missing action in request");
05209 mansession_unlock(s);
05210 return 0;
05211 }
05212
05213 if (!s->session->authenticated
05214 && strcasecmp(action, "Login")
05215 && strcasecmp(action, "Logoff")
05216 && strcasecmp(action, "Challenge")) {
05217 if (!s->session->authenticated) {
05218 report_req_not_allowed(s, action);
05219 }
05220 mansession_lock(s);
05221 astman_send_error(s, m, "Permission denied");
05222 mansession_unlock(s);
05223 return 0;
05224 }
05225
05226 if (!allowmultiplelogin
05227 && !s->session->authenticated
05228 && (!strcasecmp(action, "Login")
05229 || !strcasecmp(action, "Challenge"))) {
05230 user = astman_get_header(m, "Username");
05231
05232 if (!ast_strlen_zero(user) && check_manager_session_inuse(user)) {
05233 report_session_limit(s);
05234 sleep(1);
05235 mansession_lock(s);
05236 astman_send_error(s, m, "Login Already In Use");
05237 mansession_unlock(s);
05238 return -1;
05239 }
05240 }
05241
05242 act_found = action_find(action);
05243 if (act_found) {
05244
05245 int acted = 0;
05246
05247 if ((s->session->writeperm & act_found->authority)
05248 || act_found->authority == 0) {
05249
05250 ao2_lock(act_found);
05251 if (act_found->registered && act_found->func) {
05252 ast_debug(1, "Running action '%s'\n", act_found->action);
05253 if (act_found->module) {
05254 ast_module_ref(act_found->module);
05255 }
05256 ao2_unlock(act_found);
05257 ret = act_found->func(s, m);
05258 acted = 1;
05259 ao2_lock(act_found);
05260 if (act_found->module) {
05261 ast_module_unref(act_found->module);
05262 }
05263 }
05264 ao2_unlock(act_found);
05265 }
05266 if (!acted) {
05267
05268
05269
05270
05271
05272 report_req_not_allowed(s, action);
05273 mansession_lock(s);
05274 astman_send_error(s, m, "Permission denied");
05275 mansession_unlock(s);
05276 }
05277 ao2_t_ref(act_found, -1, "done with found action object");
05278 } else {
05279 char buf[512];
05280
05281 report_req_bad_format(s, action);
05282 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
05283 mansession_lock(s);
05284 astman_send_error(s, m, buf);
05285 mansession_unlock(s);
05286 }
05287 if (ret) {
05288 return ret;
05289 }
05290
05291
05292
05293 if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
05294 return process_events(s);
05295 } else {
05296 return ret;
05297 }
05298 }
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309 static int get_input(struct mansession *s, char *output)
05310 {
05311 int res, x;
05312 int maxlen = sizeof(s->session->inbuf) - 1;
05313 char *src = s->session->inbuf;
05314 int timeout = -1;
05315 time_t now;
05316
05317
05318
05319
05320
05321 for (x = 0; x < s->session->inlen; x++) {
05322 int cr;
05323 if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
05324 cr = 2;
05325 } else if (src[x] == '\n') {
05326 cr = 1;
05327 } else {
05328 continue;
05329 }
05330 memmove(output, src, x);
05331 output[x] = '\0';
05332 x += cr;
05333 s->session->inlen -= x;
05334 memmove(src, src + x, s->session->inlen);
05335 return 1;
05336 }
05337 if (s->session->inlen >= maxlen) {
05338
05339 ast_log(LOG_WARNING, "Discarding message from %s. Line too long: %.25s...\n", ast_sockaddr_stringify_addr(&s->session->addr), src);
05340 s->session->inlen = 0;
05341 s->parsing = MESSAGE_LINE_TOO_LONG;
05342 }
05343 res = 0;
05344 while (res == 0) {
05345
05346 if (!s->session->authenticated) {
05347 if(time(&now) == -1) {
05348 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
05349 return -1;
05350 }
05351
05352 timeout = (authtimeout - (now - s->session->authstart)) * 1000;
05353 if (timeout < 0) {
05354
05355 return 0;
05356 }
05357 }
05358
05359 ao2_lock(s->session);
05360 if (s->session->pending_event) {
05361 s->session->pending_event = 0;
05362 ao2_unlock(s->session);
05363 return 0;
05364 }
05365 s->session->waiting_thread = pthread_self();
05366 ao2_unlock(s->session);
05367
05368 res = ast_wait_for_input(s->session->fd, timeout);
05369
05370 ao2_lock(s->session);
05371 s->session->waiting_thread = AST_PTHREADT_NULL;
05372 ao2_unlock(s->session);
05373 }
05374 if (res < 0) {
05375
05376
05377
05378 if (errno == EINTR || errno == EAGAIN) {
05379 return 0;
05380 }
05381 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
05382 return -1;
05383 }
05384
05385 ao2_lock(s->session);
05386 res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
05387 if (res < 1) {
05388 res = -1;
05389 } else {
05390 s->session->inlen += res;
05391 src[s->session->inlen] = '\0';
05392 res = 0;
05393 }
05394 ao2_unlock(s->session);
05395 return res;
05396 }
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407 static void handle_parse_error(struct mansession *s, struct message *m, char *error)
05408 {
05409 mansession_lock(s);
05410 astman_send_error(s, m, error);
05411 s->parsing = MESSAGE_OKAY;
05412 mansession_unlock(s);
05413 }
05414
05415
05416
05417
05418
05419
05420
05421
05422
05423
05424 static int do_message(struct mansession *s)
05425 {
05426 struct message m = { 0 };
05427 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
05428 int res;
05429 int idx;
05430 int hdr_loss;
05431 time_t now;
05432
05433 hdr_loss = 0;
05434 for (;;) {
05435
05436 if (process_events(s)) {
05437 res = -1;
05438 break;
05439 }
05440 res = get_input(s, header_buf);
05441 if (res == 0) {
05442
05443 if (!s->session->authenticated) {
05444 if (time(&now) == -1) {
05445 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
05446 res = -1;
05447 break;
05448 }
05449
05450 if (now - s->session->authstart > authtimeout) {
05451 if (displayconnects) {
05452 ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_sockaddr_stringify_addr(&s->session->addr), authtimeout);
05453 }
05454 res = -1;
05455 break;
05456 }
05457 }
05458 continue;
05459 } else if (res > 0) {
05460
05461 if (ast_strlen_zero(header_buf)) {
05462 if (hdr_loss) {
05463 mansession_lock(s);
05464 astman_send_error(s, &m, "Too many lines in message or allocation failure");
05465 mansession_unlock(s);
05466 res = 0;
05467 } else {
05468 switch (s->parsing) {
05469 case MESSAGE_OKAY:
05470 res = process_message(s, &m) ? -1 : 0;
05471 break;
05472 case MESSAGE_LINE_TOO_LONG:
05473 handle_parse_error(s, &m, "Failed to parse message: line too long");
05474 res = 0;
05475 break;
05476 }
05477 }
05478 break;
05479 } else if (m.hdrcount < ARRAY_LEN(m.headers)) {
05480 m.headers[m.hdrcount] = ast_strdup(header_buf);
05481 if (!m.headers[m.hdrcount]) {
05482
05483 hdr_loss = 1;
05484 } else {
05485 ++m.hdrcount;
05486 }
05487 } else {
05488
05489 hdr_loss = 1;
05490 }
05491 } else {
05492
05493 break;
05494 }
05495 }
05496
05497
05498 for (idx = 0; idx < m.hdrcount; ++idx) {
05499 ast_free((void *) m.headers[idx]);
05500 }
05501 return res;
05502 }
05503
05504
05505
05506
05507
05508
05509
05510
05511
05512 static void *session_do(void *data)
05513 {
05514 struct ast_tcptls_session_instance *ser = data;
05515 struct mansession_session *session;
05516 struct mansession s = {
05517 .tcptls_session = data,
05518 };
05519 int flags;
05520 int res;
05521 struct ast_sockaddr ser_remote_address_tmp;
05522 struct protoent *p;
05523
05524 if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
05525 fclose(ser->f);
05526 ast_atomic_fetchadd_int(&unauth_sessions, -1);
05527 goto done;
05528 }
05529
05530 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
05531 session = build_mansession(&ser_remote_address_tmp);
05532
05533 if (session == NULL) {
05534 fclose(ser->f);
05535 ast_atomic_fetchadd_int(&unauth_sessions, -1);
05536 goto done;
05537 }
05538
05539
05540
05541
05542 p = getprotobyname("tcp");
05543 if (p) {
05544 int arg = 1;
05545 if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
05546 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));
05547 }
05548 } else {
05549 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");
05550 }
05551
05552
05553 flags = fcntl(ser->fd, F_GETFL);
05554 flags |= O_NONBLOCK;
05555 fcntl(ser->fd, F_SETFL, flags);
05556
05557 ao2_lock(session);
05558
05559 session->last_ev = grab_last();
05560
05561 ast_mutex_init(&s.lock);
05562
05563
05564 session->fd = s.fd = ser->fd;
05565 session->f = s.f = ser->f;
05566 ast_sockaddr_copy(&session->addr, &ser_remote_address_tmp);
05567 s.session = session;
05568
05569 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05570
05571 if(time(&session->authstart) == -1) {
05572 ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
05573 ast_atomic_fetchadd_int(&unauth_sessions, -1);
05574 ao2_unlock(session);
05575 session_destroy(session);
05576 goto done;
05577 }
05578 ao2_unlock(session);
05579
05580
05581
05582
05583
05584 ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0);
05585
05586 ast_tcptls_stream_set_timeout_sequence(ser->stream_cookie,
05587 ast_tvnow(), authtimeout * 1000);
05588
05589 astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION);
05590 for (;;) {
05591 if ((res = do_message(&s)) < 0 || s.write_error) {
05592 break;
05593 }
05594 if (session->authenticated) {
05595 ast_tcptls_stream_set_timeout_disable(ser->stream_cookie);
05596 }
05597 }
05598
05599 if (session->authenticated) {
05600 if (manager_displayconnects(session)) {
05601 ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
05602 }
05603 } else {
05604 ast_atomic_fetchadd_int(&unauth_sessions, -1);
05605 if (displayconnects) {
05606 ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
05607 }
05608 }
05609
05610 session_destroy(session);
05611
05612 ast_mutex_destroy(&s.lock);
05613 done:
05614 ao2_ref(ser, -1);
05615 ser = NULL;
05616 return NULL;
05617 }
05618
05619
05620 static void purge_sessions(int n_max)
05621 {
05622 struct ao2_container *sessions;
05623 struct mansession_session *session;
05624 time_t now = time(NULL);
05625 struct ao2_iterator i;
05626
05627 sessions = ao2_global_obj_ref(mgr_sessions);
05628 if (!sessions) {
05629 return;
05630 }
05631 i = ao2_iterator_init(sessions, 0);
05632 ao2_ref(sessions, -1);
05633 while ((session = ao2_iterator_next(&i)) && n_max > 0) {
05634 ao2_lock(session);
05635 if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
05636 if (session->authenticated
05637 && VERBOSITY_ATLEAST(2)
05638 && manager_displayconnects(session)) {
05639 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
05640 session->username, ast_sockaddr_stringify_addr(&session->addr));
05641 }
05642 ao2_unlock(session);
05643 session_destroy(session);
05644 n_max--;
05645 } else {
05646 ao2_unlock(session);
05647 unref_mansession(session);
05648 }
05649 }
05650 ao2_iterator_destroy(&i);
05651 }
05652
05653
05654
05655
05656
05657 static int append_event(const char *str, int category)
05658 {
05659 struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
05660 static int seq;
05661
05662 if (!tmp) {
05663 return -1;
05664 }
05665
05666
05667 tmp->usecount = 0;
05668 tmp->category = category;
05669 tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
05670 tmp->tv = ast_tvnow();
05671 AST_RWLIST_NEXT(tmp, eq_next) = NULL;
05672 strcpy(tmp->eventdata, str);
05673
05674 AST_RWLIST_WRLOCK(&all_events);
05675 AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
05676 AST_RWLIST_UNLOCK(&all_events);
05677
05678 return 0;
05679 }
05680
05681 AST_THREADSTORAGE(manager_event_funcbuf);
05682
05683 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
05684 {
05685 struct manager_channel_variable *var;
05686
05687 AST_RWLIST_RDLOCK(&channelvars);
05688 AST_LIST_TRAVERSE(&channelvars, var, entry) {
05689 const char *val;
05690 struct ast_str *res;
05691
05692 if (var->isfunc) {
05693 res = ast_str_thread_get(&manager_event_funcbuf, 16);
05694 if (res && ast_func_read2(chan, var->name, &res, 0) == 0) {
05695 val = ast_str_buffer(res);
05696 } else {
05697 val = NULL;
05698 }
05699 } else {
05700 val = pbx_builtin_getvar_helper(chan, var->name);
05701 }
05702 ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, val ? val : "");
05703 }
05704 AST_RWLIST_UNLOCK(&channelvars);
05705 }
05706
05707
05708 AST_THREADSTORAGE(manager_event_buf);
05709 #define MANAGER_EVENT_BUF_INITSIZE 256
05710
05711 int __ast_manager_event_multichan(int category, const char *event, int chancount,
05712 struct ast_channel **chans, const char *file, int line, const char *func,
05713 const char *fmt, ...)
05714 {
05715 RAII_VAR(struct ao2_container *, sessions, ao2_global_obj_ref(mgr_sessions), ao2_cleanup);
05716 struct mansession_session *session;
05717 struct manager_custom_hook *hook;
05718 struct ast_str *auth = ast_str_alloca(80);
05719 const char *cat_str;
05720 va_list ap;
05721 struct timeval now;
05722 struct ast_str *buf;
05723 int i;
05724
05725 if (!(sessions && ao2_container_count(sessions)) && AST_RWLIST_EMPTY(&manager_hooks)) {
05726 return 0;
05727 }
05728
05729 if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) {
05730 return -1;
05731 }
05732
05733 cat_str = authority_to_str(category, &auth);
05734 ast_str_set(&buf, 0,
05735 "Event: %s\r\nPrivilege: %s\r\n",
05736 event, cat_str);
05737
05738 if (timestampevents) {
05739 now = ast_tvnow();
05740 ast_str_append(&buf, 0,
05741 "Timestamp: %ld.%06lu\r\n",
05742 (long)now.tv_sec, (unsigned long) now.tv_usec);
05743 }
05744 if (manager_debug) {
05745 static int seq;
05746 ast_str_append(&buf, 0,
05747 "SequenceNumber: %d\r\n",
05748 ast_atomic_fetchadd_int(&seq, 1));
05749 ast_str_append(&buf, 0,
05750 "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
05751 }
05752
05753 va_start(ap, fmt);
05754 ast_str_append_va(&buf, 0, fmt, ap);
05755 va_end(ap);
05756 for (i = 0; i < chancount; i++) {
05757 append_channel_vars(&buf, chans[i]);
05758 }
05759
05760 ast_str_append(&buf, 0, "\r\n");
05761
05762 append_event(ast_str_buffer(buf), category);
05763
05764
05765 if (sessions) {
05766 struct ao2_iterator i;
05767 i = ao2_iterator_init(sessions, 0);
05768 while ((session = ao2_iterator_next(&i))) {
05769 ao2_lock(session);
05770 if (session->waiting_thread != AST_PTHREADT_NULL) {
05771 pthread_kill(session->waiting_thread, SIGURG);
05772 } else {
05773
05774
05775
05776
05777
05778 session->pending_event = 1;
05779 }
05780 ao2_unlock(session);
05781 unref_mansession(session);
05782 }
05783 ao2_iterator_destroy(&i);
05784 }
05785
05786 if (!AST_RWLIST_EMPTY(&manager_hooks)) {
05787 AST_RWLIST_RDLOCK(&manager_hooks);
05788 AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
05789 hook->helper(category, event, ast_str_buffer(buf));
05790 }
05791 AST_RWLIST_UNLOCK(&manager_hooks);
05792 }
05793
05794 return 0;
05795 }
05796
05797
05798
05799
05800 int ast_manager_unregister(const char *action)
05801 {
05802 struct manager_action *cur;
05803
05804 AST_RWLIST_WRLOCK(&actions);
05805 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
05806 if (!strcasecmp(action, cur->action)) {
05807 AST_RWLIST_REMOVE_CURRENT(list);
05808 break;
05809 }
05810 }
05811 AST_RWLIST_TRAVERSE_SAFE_END;
05812 AST_RWLIST_UNLOCK(&actions);
05813
05814 if (cur) {
05815
05816
05817
05818
05819 ao2_lock(cur);
05820 cur->registered = 0;
05821 ao2_unlock(cur);
05822
05823 ao2_t_ref(cur, -1, "action object removed from list");
05824 ast_verb(2, "Manager unregistered action %s\n", action);
05825 }
05826
05827 return 0;
05828 }
05829
05830 static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
05831 {
05832
05833 char hint[512];
05834
05835 ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
05836
05837 switch(info->reason) {
05838 case AST_HINT_UPDATE_DEVICE:
05839
05840
05841
05842
05843
05844 manager_event(EVENT_FLAG_CALL, "ExtensionStatus",
05845 "Exten: %s\r\n"
05846 "Context: %s\r\n"
05847 "Hint: %s\r\n"
05848 "Status: %d\r\n",
05849 exten,
05850 context,
05851 hint,
05852 info->exten_state);
05853 break;
05854 case AST_HINT_UPDATE_PRESENCE:
05855
05856
05857
05858
05859
05860 manager_event(EVENT_FLAG_CALL, "PresenceStatus",
05861 "Exten: %s\r\n"
05862 "Context: %s\r\n"
05863 "Hint: %s\r\n"
05864 "Status: %s\r\n"
05865 "Subtype: %s\r\n"
05866 "Message: %s\r\n",
05867 exten,
05868 context,
05869 hint,
05870 ast_presence_state2str(info->presence_state),
05871 info->presence_subtype,
05872 info->presence_message);
05873 break;
05874 }
05875 return 0;
05876 }
05877
05878 static int ast_manager_register_struct(struct manager_action *act)
05879 {
05880 struct manager_action *cur, *prev = NULL;
05881
05882 AST_RWLIST_WRLOCK(&actions);
05883 AST_RWLIST_TRAVERSE(&actions, cur, list) {
05884 int ret;
05885
05886 ret = strcasecmp(cur->action, act->action);
05887 if (ret == 0) {
05888 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
05889 AST_RWLIST_UNLOCK(&actions);
05890 return -1;
05891 }
05892 if (ret > 0) {
05893 prev = cur;
05894 break;
05895 }
05896 }
05897
05898 ao2_t_ref(act, +1, "action object added to list");
05899 act->registered = 1;
05900 if (prev) {
05901 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
05902 } else {
05903 AST_RWLIST_INSERT_HEAD(&actions, act, list);
05904 }
05905
05906 ast_verb(2, "Manager registered action %s\n", act->action);
05907
05908 AST_RWLIST_UNLOCK(&actions);
05909
05910 return 0;
05911 }
05912
05913
05914
05915
05916
05917
05918
05919
05920
05921 static void action_destroy(void *obj)
05922 {
05923 struct manager_action *doomed = obj;
05924
05925 if (doomed->synopsis) {
05926
05927 ast_string_field_free_memory(doomed);
05928 }
05929 }
05930
05931
05932
05933 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
05934 {
05935 struct manager_action *cur;
05936
05937 cur = ao2_alloc(sizeof(*cur), action_destroy);
05938 if (!cur) {
05939 return -1;
05940 }
05941 if (ast_string_field_init(cur, 128)) {
05942 ao2_t_ref(cur, -1, "action object creation failed");
05943 return -1;
05944 }
05945
05946 cur->action = action;
05947 cur->authority = auth;
05948 cur->func = func;
05949 cur->module = module;
05950 #ifdef AST_XML_DOCS
05951 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
05952 char *tmpxml;
05953
05954 tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
05955 ast_string_field_set(cur, synopsis, tmpxml);
05956 ast_free(tmpxml);
05957
05958 tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
05959 ast_string_field_set(cur, syntax, tmpxml);
05960 ast_free(tmpxml);
05961
05962 tmpxml = ast_xmldoc_build_description("manager", action, NULL);
05963 ast_string_field_set(cur, description, tmpxml);
05964 ast_free(tmpxml);
05965
05966 tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
05967 ast_string_field_set(cur, seealso, tmpxml);
05968 ast_free(tmpxml);
05969
05970 tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
05971 ast_string_field_set(cur, arguments, tmpxml);
05972 ast_free(tmpxml);
05973
05974 cur->docsrc = AST_XML_DOC;
05975 } else
05976 #endif
05977 {
05978 ast_string_field_set(cur, synopsis, synopsis);
05979 ast_string_field_set(cur, description, description);
05980 #ifdef AST_XML_DOCS
05981 cur->docsrc = AST_STATIC_DOC;
05982 #endif
05983 }
05984 if (ast_manager_register_struct(cur)) {
05985 ao2_t_ref(cur, -1, "action object registration failed");
05986 return -1;
05987 }
05988
05989 ao2_t_ref(cur, -1, "action object registration successful");
05990 return 0;
05991 }
05992
05993
05994
05995
05996
05997
05998
05999
06000
06001
06002
06003
06004
06005
06006
06007 enum output_format {
06008 FORMAT_RAW,
06009 FORMAT_HTML,
06010 FORMAT_XML,
06011 };
06012
06013 static const char * const contenttype[] = {
06014 [FORMAT_RAW] = "plain",
06015 [FORMAT_HTML] = "html",
06016 [FORMAT_XML] = "xml",
06017 };
06018
06019
06020
06021
06022
06023
06024 static struct mansession_session *find_session(uint32_t ident, int incinuse)
06025 {
06026 struct ao2_container *sessions;
06027 struct mansession_session *session;
06028 struct ao2_iterator i;
06029
06030 if (ident == 0) {
06031 return NULL;
06032 }
06033
06034 sessions = ao2_global_obj_ref(mgr_sessions);
06035 if (!sessions) {
06036 return NULL;
06037 }
06038 i = ao2_iterator_init(sessions, 0);
06039 ao2_ref(sessions, -1);
06040 while ((session = ao2_iterator_next(&i))) {
06041 ao2_lock(session);
06042 if (session->managerid == ident && !session->needdestroy) {
06043 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
06044 break;
06045 }
06046 ao2_unlock(session);
06047 unref_mansession(session);
06048 }
06049 ao2_iterator_destroy(&i);
06050
06051 return session;
06052 }
06053
06054
06055
06056
06057
06058
06059
06060
06061
06062
06063 static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
06064 {
06065 struct mansession_session *session;
06066 struct ao2_container *sessions;
06067 struct ao2_iterator i;
06068
06069 if (nonce == 0 || username == NULL || stale == NULL) {
06070 return NULL;
06071 }
06072
06073 sessions = ao2_global_obj_ref(mgr_sessions);
06074 if (!sessions) {
06075 return NULL;
06076 }
06077 i = ao2_iterator_init(sessions, 0);
06078 ao2_ref(sessions, -1);
06079 while ((session = ao2_iterator_next(&i))) {
06080 ao2_lock(session);
06081 if (!strcasecmp(session->username, username) && session->managerid == nonce) {
06082 *stale = 0;
06083 break;
06084 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
06085 *stale = 1;
06086 break;
06087 }
06088 ao2_unlock(session);
06089 unref_mansession(session);
06090 }
06091 ao2_iterator_destroy(&i);
06092
06093 return session;
06094 }
06095
06096 int astman_is_authed(uint32_t ident)
06097 {
06098 int authed;
06099 struct mansession_session *session;
06100
06101 if (!(session = find_session(ident, 0)))
06102 return 0;
06103
06104 authed = (session->authenticated != 0);
06105
06106 ao2_unlock(session);
06107 unref_mansession(session);
06108
06109 return authed;
06110 }
06111
06112 int astman_verify_session_readpermissions(uint32_t ident, int perm)
06113 {
06114 int result = 0;
06115 struct mansession_session *session;
06116 struct ao2_container *sessions;
06117 struct ao2_iterator i;
06118
06119 if (ident == 0) {
06120 return 0;
06121 }
06122
06123 sessions = ao2_global_obj_ref(mgr_sessions);
06124 if (!sessions) {
06125 return 0;
06126 }
06127 i = ao2_iterator_init(sessions, 0);
06128 ao2_ref(sessions, -1);
06129 while ((session = ao2_iterator_next(&i))) {
06130 ao2_lock(session);
06131 if ((session->managerid == ident) && (session->readperm & perm)) {
06132 result = 1;
06133 ao2_unlock(session);
06134 unref_mansession(session);
06135 break;
06136 }
06137 ao2_unlock(session);
06138 unref_mansession(session);
06139 }
06140 ao2_iterator_destroy(&i);
06141
06142 return result;
06143 }
06144
06145 int astman_verify_session_writepermissions(uint32_t ident, int perm)
06146 {
06147 int result = 0;
06148 struct mansession_session *session;
06149 struct ao2_container *sessions;
06150 struct ao2_iterator i;
06151
06152 if (ident == 0) {
06153 return 0;
06154 }
06155
06156 sessions = ao2_global_obj_ref(mgr_sessions);
06157 if (!sessions) {
06158 return 0;
06159 }
06160 i = ao2_iterator_init(sessions, 0);
06161 ao2_ref(sessions, -1);
06162 while ((session = ao2_iterator_next(&i))) {
06163 ao2_lock(session);
06164 if ((session->managerid == ident) && (session->writeperm & perm)) {
06165 result = 1;
06166 ao2_unlock(session);
06167 unref_mansession(session);
06168 break;
06169 }
06170 ao2_unlock(session);
06171 unref_mansession(session);
06172 }
06173 ao2_iterator_destroy(&i);
06174
06175 return result;
06176 }
06177
06178
06179
06180
06181
06182
06183 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
06184 {
06185
06186 char buf[256];
06187 char *dst = buf;
06188 int space = sizeof(buf);
06189
06190 for ( ; *src || dst != buf ; src++) {
06191 if (*src == '\0' || space < 10) {
06192 *dst++ = '\0';
06193 ast_str_append(out, 0, "%s", buf);
06194 dst = buf;
06195 space = sizeof(buf);
06196 if (*src == '\0') {
06197 break;
06198 }
06199 }
06200
06201 if ( (mode & 2) && !isalnum(*src)) {
06202 *dst++ = '_';
06203 space--;
06204 continue;
06205 }
06206 switch (*src) {
06207 case '<':
06208 strcpy(dst, "<");
06209 dst += 4;
06210 space -= 4;
06211 break;
06212 case '>':
06213 strcpy(dst, ">");
06214 dst += 4;
06215 space -= 4;
06216 break;
06217 case '\"':
06218 strcpy(dst, """);
06219 dst += 6;
06220 space -= 6;
06221 break;
06222 case '\'':
06223 strcpy(dst, "'");
06224 dst += 6;
06225 space -= 6;
06226 break;
06227 case '&':
06228 strcpy(dst, "&");
06229 dst += 5;
06230 space -= 5;
06231 break;
06232
06233 default:
06234 *dst++ = mode ? tolower(*src) : *src;
06235 space--;
06236 }
06237 }
06238 }
06239
06240 struct variable_count {
06241 char *varname;
06242 int count;
06243 };
06244
06245 static int variable_count_hash_fn(const void *vvc, const int flags)
06246 {
06247 const struct variable_count *vc = vvc;
06248
06249 return ast_str_hash(vc->varname);
06250 }
06251
06252 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
06253 {
06254
06255
06256
06257
06258 struct variable_count *vc = obj;
06259 char *str = vstr;
06260 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
06261 }
06262
06263
06264
06265
06266
06267
06268
06269
06270
06271
06272
06273
06274
06275
06276
06277
06278
06279
06280
06281
06282
06283
06284
06285
06286
06287
06288
06289
06290
06291 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
06292 {
06293 struct ast_variable *v;
06294 const char *dest = NULL;
06295 char *var, *val;
06296 const char *objtype = NULL;
06297 int in_data = 0;
06298 int inobj = 0;
06299 int xml = (format == FORMAT_XML);
06300 struct variable_count *vc = NULL;
06301 struct ao2_container *vco = NULL;
06302
06303 if (xml) {
06304
06305 for (v = get_vars; v; v = v->next) {
06306 if (!strcasecmp(v->name, "ajaxdest")) {
06307 dest = v->value;
06308 } else if (!strcasecmp(v->name, "ajaxobjtype")) {
06309 objtype = v->value;
06310 }
06311 }
06312 if (ast_strlen_zero(dest)) {
06313 dest = "unknown";
06314 }
06315 if (ast_strlen_zero(objtype)) {
06316 objtype = "generic";
06317 }
06318 }
06319
06320
06321 while (in && *in) {
06322 val = strsep(&in, "\r\n");
06323 if (in && *in == '\n') {
06324 in++;
06325 }
06326 ast_trim_blanks(val);
06327 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
06328 if (ast_strlen_zero(val)) {
06329
06330 if (in_data) {
06331
06332 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
06333 in_data = 0;
06334 }
06335
06336 if (inobj) {
06337
06338 ast_str_append(out, 0, xml ? " /></response>\n" :
06339 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
06340 inobj = 0;
06341 ao2_ref(vco, -1);
06342 vco = NULL;
06343 }
06344 continue;
06345 }
06346
06347 if (!inobj) {
06348
06349 if (xml) {
06350 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
06351 }
06352 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
06353 inobj = 1;
06354 }
06355
06356 if (in_data) {
06357
06358
06359 ast_str_append(out, 0, xml ? "\n" : "<br>\n");
06360 xml_copy_escape(out, val, 0);
06361 continue;
06362 }
06363
06364
06365 var = strsep(&val, ":");
06366 if (val) {
06367
06368 val = ast_skip_blanks(val);
06369 ast_trim_blanks(var);
06370 } else {
06371
06372 val = var;
06373 var = "Opaque-data";
06374 in_data = 1;
06375 }
06376
06377
06378 ast_str_append(out, 0, xml ? " " : "<tr><td>");
06379 if ((vc = ao2_find(vco, var, 0))) {
06380 vc->count++;
06381 } else {
06382
06383 vc = ao2_alloc(sizeof(*vc), NULL);
06384 vc->varname = var;
06385 vc->count = 1;
06386 ao2_link(vco, vc);
06387 }
06388
06389 xml_copy_escape(out, var, xml ? 1 | 2 : 0);
06390 if (vc->count > 1) {
06391 ast_str_append(out, 0, "-%d", vc->count);
06392 }
06393 ao2_ref(vc, -1);
06394 ast_str_append(out, 0, xml ? "='" : "</td><td>");
06395 xml_copy_escape(out, val, 0);
06396 if (!in_data || !*in) {
06397 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
06398 }
06399 }
06400
06401 if (inobj) {
06402 ast_str_append(out, 0, xml ? " /></response>\n" :
06403 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
06404 ao2_ref(vco, -1);
06405 }
06406 }
06407
06408 static void close_mansession_file(struct mansession *s)
06409 {
06410 if (s->f) {
06411 if (fclose(s->f)) {
06412 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
06413 }
06414 s->f = NULL;
06415 s->fd = -1;
06416 } else if (s->fd != -1) {
06417
06418
06419
06420
06421
06422 shutdown(s->fd, SHUT_RDWR);
06423 if (close(s->fd)) {
06424 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
06425 }
06426 s->fd = -1;
06427 } else {
06428 ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
06429 }
06430 }
06431
06432 static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
06433 {
06434 char *buf;
06435 size_t l;
06436
06437 if (!s->f)
06438 return;
06439
06440
06441 fprintf(s->f, "%c", 0);
06442 fflush(s->f);
06443
06444 if ((l = ftell(s->f)) > 0) {
06445 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
06446 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
06447 } else {
06448 if (format == FORMAT_XML || format == FORMAT_HTML) {
06449 xml_translate(out, buf, params, format);
06450 } else {
06451 ast_str_append(out, 0, "%s", buf);
06452 }
06453 munmap(buf, l);
06454 }
06455 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
06456 xml_translate(out, "", params, format);
06457 }
06458
06459 close_mansession_file(s);
06460 }
06461
06462 static int generic_http_callback(struct ast_tcptls_session_instance *ser,
06463 enum ast_http_method method,
06464 enum output_format format,
06465 const struct ast_sockaddr *remote_address, const char *uri,
06466 struct ast_variable *get_params,
06467 struct ast_variable *headers)
06468 {
06469 struct mansession s = { .session = NULL, .tcptls_session = ser };
06470 struct mansession_session *session = NULL;
06471 uint32_t ident = 0;
06472 int blastaway = 0;
06473 struct ast_variable *v, *cookies, *params = get_params;
06474 char template[] = "/tmp/ast-http-XXXXXX";
06475 struct ast_str *http_header = NULL, *out = NULL;
06476 struct message m = { 0 };
06477 unsigned int idx;
06478 size_t hdrlen;
06479
06480 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
06481 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
06482 return -1;
06483 }
06484
06485 cookies = ast_http_get_cookies(headers);
06486 for (v = cookies; v; v = v->next) {
06487 if (!strcasecmp(v->name, "mansession_id")) {
06488 sscanf(v->value, "%30x", &ident);
06489 break;
06490 }
06491 }
06492 if (cookies) {
06493 ast_variables_destroy(cookies);
06494 }
06495
06496 if (!(session = find_session(ident, 1))) {
06497
06498
06499
06500
06501
06502 if (!(session = build_mansession(remote_address))) {
06503 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06504 return -1;
06505 }
06506 ao2_lock(session);
06507 session->send_events = 0;
06508 session->inuse = 1;
06509
06510
06511
06512
06513
06514 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
06515 session->last_ev = grab_last();
06516 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06517 }
06518 ao2_unlock(session);
06519
06520 http_header = ast_str_create(128);
06521 out = ast_str_create(2048);
06522
06523 ast_mutex_init(&s.lock);
06524
06525 if (http_header == NULL || out == NULL) {
06526 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06527 goto generic_callback_out;
06528 }
06529
06530 s.session = session;
06531 s.fd = mkstemp(template);
06532 unlink(template);
06533 if (s.fd <= -1) {
06534 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06535 goto generic_callback_out;
06536 }
06537 s.f = fdopen(s.fd, "w+");
06538 if (!s.f) {
06539 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06540 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06541 close(s.fd);
06542 goto generic_callback_out;
06543 }
06544
06545 if (method == AST_HTTP_POST) {
06546 params = ast_http_get_post_vars(ser, headers);
06547 }
06548
06549 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06550 hdrlen = strlen(v->name) + strlen(v->value) + 3;
06551 m.headers[m.hdrcount] = ast_malloc(hdrlen);
06552 if (!m.headers[m.hdrcount]) {
06553
06554 continue;
06555 }
06556 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06557 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06558 ++m.hdrcount;
06559 }
06560
06561 if (process_message(&s, &m)) {
06562 if (session->authenticated) {
06563 if (manager_displayconnects(session)) {
06564 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
06565 }
06566 } else {
06567 if (displayconnects) {
06568 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
06569 }
06570 }
06571 session->needdestroy = 1;
06572 }
06573
06574
06575 for (idx = 0; idx < m.hdrcount; ++idx) {
06576 ast_free((void *) m.headers[idx]);
06577 m.headers[idx] = NULL;
06578 }
06579
06580 ast_str_append(&http_header, 0,
06581 "Content-type: text/%s\r\n"
06582 "Cache-Control: no-cache;\r\n"
06583 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
06584 "Pragma: SuppressEvents\r\n",
06585 contenttype[format],
06586 session->managerid, httptimeout);
06587
06588 if (format == FORMAT_XML) {
06589 ast_str_append(&out, 0, "<ajax-response>\n");
06590 } else if (format == FORMAT_HTML) {
06591
06592
06593
06594
06595
06596
06597 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
06598 #define TEST_STRING \
06599 "<form action=\"manager\" method=\"post\">\n\
06600 Action: <select name=\"action\">\n\
06601 <option value=\"\">-----></option>\n\
06602 <option value=\"login\">login</option>\n\
06603 <option value=\"command\">Command</option>\n\
06604 <option value=\"waitevent\">waitevent</option>\n\
06605 <option value=\"listcommands\">listcommands</option>\n\
06606 </select>\n\
06607 or <input name=\"action\"><br/>\n\
06608 CLI Command <input name=\"command\"><br>\n\
06609 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
06610 <input type=\"submit\">\n</form>\n"
06611
06612 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>");
06613 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
06614 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
06615 ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
06616 }
06617
06618 process_output(&s, &out, params, format);
06619
06620 if (format == FORMAT_XML) {
06621 ast_str_append(&out, 0, "</ajax-response>\n");
06622 } else if (format == FORMAT_HTML) {
06623 ast_str_append(&out, 0, "</table></body>\r\n");
06624 }
06625
06626 ao2_lock(session);
06627
06628 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
06629
06630 if (session->needdestroy) {
06631 if (session->inuse == 1) {
06632 ast_debug(1, "Need destroy, doing it now!\n");
06633 blastaway = 1;
06634 } else {
06635 ast_debug(1, "Need destroy, but can't do it yet!\n");
06636 if (session->waiting_thread != AST_PTHREADT_NULL) {
06637 pthread_kill(session->waiting_thread, SIGURG);
06638 }
06639 session->inuse--;
06640 }
06641 } else {
06642 session->inuse--;
06643 }
06644 ao2_unlock(session);
06645
06646 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06647 http_header = out = NULL;
06648
06649 generic_callback_out:
06650 ast_mutex_destroy(&s.lock);
06651
06652
06653
06654 if (method == AST_HTTP_POST && params) {
06655 ast_variables_destroy(params);
06656 }
06657 ast_free(http_header);
06658 ast_free(out);
06659
06660 if (session && blastaway) {
06661 session_destroy(session);
06662 } else if (session && session->f) {
06663 fclose(session->f);
06664 session->f = NULL;
06665 }
06666
06667 return 0;
06668 }
06669
06670 static int auth_http_callback(struct ast_tcptls_session_instance *ser,
06671 enum ast_http_method method,
06672 enum output_format format,
06673 const struct ast_sockaddr *remote_address, const char *uri,
06674 struct ast_variable *get_params,
06675 struct ast_variable *headers)
06676 {
06677 struct mansession_session *session = NULL;
06678 struct mansession s = { .session = NULL, .tcptls_session = ser };
06679 struct ast_variable *v, *params = get_params;
06680 char template[] = "/tmp/ast-http-XXXXXX";
06681 struct ast_str *http_header = NULL, *out = NULL;
06682 size_t result_size = 512;
06683 struct message m = { 0 };
06684 unsigned int idx;
06685 size_t hdrlen;
06686
06687 time_t time_now = time(NULL);
06688 unsigned long nonce = 0, nc;
06689 struct ast_http_digest d = { NULL, };
06690 struct ast_manager_user *user = NULL;
06691 int stale = 0;
06692 char resp_hash[256]="";
06693
06694 char u_username[80];
06695 int u_readperm;
06696 int u_writeperm;
06697 int u_writetimeout;
06698 int u_displayconnects;
06699
06700 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
06701 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
06702 return -1;
06703 }
06704
06705
06706 for (v = headers; v; v = v->next) {
06707 if (!strcasecmp(v->name, "Authorization")) {
06708 break;
06709 }
06710 }
06711
06712 if (!v || ast_strlen_zero(v->value)) {
06713 goto out_401;
06714 }
06715
06716
06717 if (ast_string_field_init(&d, 128)) {
06718 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06719 return -1;
06720 }
06721
06722 if (ast_parse_digest(v->value, &d, 0, 1)) {
06723
06724 nonce = 0;
06725 goto out_401;
06726 }
06727 if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
06728 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
06729 nonce = 0;
06730 goto out_401;
06731 }
06732
06733 AST_RWLIST_WRLOCK(&users);
06734 user = get_manager_by_name_locked(d.username);
06735 if(!user) {
06736 AST_RWLIST_UNLOCK(&users);
06737 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
06738 nonce = 0;
06739 goto out_401;
06740 }
06741
06742
06743 if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
06744 AST_RWLIST_UNLOCK(&users);
06745 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
06746 ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
06747 return -1;
06748 }
06749
06750
06751
06752
06753 {
06754 char a2[256];
06755 char a2_hash[256];
06756 char resp[256];
06757
06758
06759 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
06760 ast_md5_hash(a2_hash, a2);
06761
06762 if (d.qop) {
06763
06764 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
06765 } else {
06766
06767 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
06768 }
06769 ast_md5_hash(resp_hash, resp);
06770 }
06771
06772 if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
06773
06774 AST_RWLIST_UNLOCK(&users);
06775 nonce = 0;
06776 goto out_401;
06777 }
06778
06779
06780
06781
06782
06783 ast_copy_string(u_username, user->username, sizeof(u_username));
06784 u_readperm = user->readperm;
06785 u_writeperm = user->writeperm;
06786 u_displayconnects = user->displayconnects;
06787 u_writetimeout = user->writetimeout;
06788 AST_RWLIST_UNLOCK(&users);
06789
06790 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
06791
06792
06793
06794
06795 if (!(session = build_mansession(remote_address))) {
06796 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06797 return -1;
06798 }
06799 ao2_lock(session);
06800
06801 ast_copy_string(session->username, u_username, sizeof(session->username));
06802 session->managerid = nonce;
06803 session->last_ev = grab_last();
06804 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06805
06806 session->readperm = u_readperm;
06807 session->writeperm = u_writeperm;
06808 session->writetimeout = u_writetimeout;
06809
06810 if (u_displayconnects) {
06811 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
06812 }
06813 session->noncetime = session->sessionstart = time_now;
06814 session->authenticated = 1;
06815 } else if (stale) {
06816
06817
06818
06819
06820
06821
06822
06823
06824
06825
06826
06827
06828 nonce = session->managerid;
06829 ao2_unlock(session);
06830 stale = 1;
06831 goto out_401;
06832 } else {
06833 sscanf(d.nc, "%30lx", &nc);
06834 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
06835
06836
06837
06838
06839
06840
06841
06842 session->nc = 0;
06843 session->oldnonce = session->managerid;
06844 nonce = session->managerid = ast_random();
06845 session->noncetime = time_now;
06846 ao2_unlock(session);
06847 stale = 1;
06848 goto out_401;
06849 } else {
06850 session->nc = nc;
06851 }
06852 }
06853
06854
06855
06856 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
06857 ao2_unlock(session);
06858
06859 ast_mutex_init(&s.lock);
06860 s.session = session;
06861 s.fd = mkstemp(template);
06862 unlink(template);
06863 if (s.fd <= -1) {
06864 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06865 goto auth_callback_out;
06866 }
06867 s.f = fdopen(s.fd, "w+");
06868 if (!s.f) {
06869 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06870 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06871 close(s.fd);
06872 goto auth_callback_out;
06873 }
06874
06875 if (method == AST_HTTP_POST) {
06876 params = ast_http_get_post_vars(ser, headers);
06877 }
06878
06879 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06880 hdrlen = strlen(v->name) + strlen(v->value) + 3;
06881 m.headers[m.hdrcount] = ast_malloc(hdrlen);
06882 if (!m.headers[m.hdrcount]) {
06883
06884 continue;
06885 }
06886 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06887 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06888 ++m.hdrcount;
06889 }
06890
06891 if (process_message(&s, &m)) {
06892 if (u_displayconnects) {
06893 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
06894 }
06895
06896 session->needdestroy = 1;
06897 }
06898
06899
06900 for (idx = 0; idx < m.hdrcount; ++idx) {
06901 ast_free((void *) m.headers[idx]);
06902 m.headers[idx] = NULL;
06903 }
06904
06905 if (s.f) {
06906 result_size = ftell(s.f);
06907 }
06908
06909 http_header = ast_str_create(80);
06910 out = ast_str_create(result_size * 2 + 512);
06911
06912 if (http_header == NULL || out == NULL) {
06913 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06914 goto auth_callback_out;
06915 }
06916
06917 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
06918
06919 if (format == FORMAT_XML) {
06920 ast_str_append(&out, 0, "<ajax-response>\n");
06921 } else if (format == FORMAT_HTML) {
06922 ast_str_append(&out, 0,
06923 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
06924 "<html><head>\r\n"
06925 "<title>Asterisk™ Manager Interface</title>\r\n"
06926 "</head><body style=\"background-color: #ffffff;\">\r\n"
06927 "<form method=\"POST\">\r\n"
06928 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
06929 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
06930 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
06931 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
06932 }
06933
06934 process_output(&s, &out, params, format);
06935
06936 if (format == FORMAT_XML) {
06937 ast_str_append(&out, 0, "</ajax-response>\n");
06938 } else if (format == FORMAT_HTML) {
06939 ast_str_append(&out, 0, "</table></form></body></html>\r\n");
06940 }
06941
06942 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06943 http_header = out = NULL;
06944
06945 auth_callback_out:
06946 ast_mutex_destroy(&s.lock);
06947
06948
06949 if (method == AST_HTTP_POST && params) {
06950 ast_variables_destroy(params);
06951 }
06952
06953 ast_free(http_header);
06954 ast_free(out);
06955
06956 ao2_lock(session);
06957 if (session->f) {
06958 fclose(session->f);
06959 }
06960 session->f = NULL;
06961 session->fd = -1;
06962 ao2_unlock(session);
06963
06964 if (session->needdestroy) {
06965 ast_debug(1, "Need destroy, doing it now!\n");
06966 session_destroy(session);
06967 }
06968 ast_string_field_free_memory(&d);
06969 return 0;
06970
06971 out_401:
06972 if (!nonce) {
06973 nonce = ast_random();
06974 }
06975
06976 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
06977 ast_string_field_free_memory(&d);
06978 return 0;
06979 }
06980
06981 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)
06982 {
06983 int retval;
06984 struct ast_sockaddr ser_remote_address_tmp;
06985
06986 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
06987 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06988 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
06989 return retval;
06990 }
06991
06992 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)
06993 {
06994 int retval;
06995 struct ast_sockaddr ser_remote_address_tmp;
06996
06997 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
06998 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06999 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07000 return retval;
07001 }
07002
07003 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)
07004 {
07005 int retval;
07006 struct ast_sockaddr ser_remote_address_tmp;
07007
07008 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07009 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
07010 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07011 return retval;
07012 }
07013
07014 static struct ast_http_uri rawmanuri = {
07015 .description = "Raw HTTP Manager Event Interface",
07016 .uri = "rawman",
07017 .callback = rawman_http_callback,
07018 .data = NULL,
07019 .key = __FILE__,
07020 };
07021
07022 static struct ast_http_uri manageruri = {
07023 .description = "HTML Manager Event Interface",
07024 .uri = "manager",
07025 .callback = manager_http_callback,
07026 .data = NULL,
07027 .key = __FILE__,
07028 };
07029
07030 static struct ast_http_uri managerxmluri = {
07031 .description = "XML Manager Event Interface",
07032 .uri = "mxml",
07033 .callback = mxml_http_callback,
07034 .data = NULL,
07035 .key = __FILE__,
07036 };
07037
07038
07039
07040 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)
07041 {
07042 int retval;
07043 struct ast_sockaddr ser_remote_address_tmp;
07044
07045 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07046 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
07047 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07048 return retval;
07049 }
07050
07051 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)
07052 {
07053 int retval;
07054 struct ast_sockaddr ser_remote_address_tmp;
07055
07056 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07057 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
07058 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07059 return retval;
07060 }
07061
07062 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)
07063 {
07064 int retval;
07065 struct ast_sockaddr ser_remote_address_tmp;
07066
07067 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07068 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
07069 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07070 return retval;
07071 }
07072
07073 static struct ast_http_uri arawmanuri = {
07074 .description = "Raw HTTP Manager Event Interface w/Digest authentication",
07075 .uri = "arawman",
07076 .has_subtree = 0,
07077 .callback = auth_rawman_http_callback,
07078 .data = NULL,
07079 .key = __FILE__,
07080 };
07081
07082 static struct ast_http_uri amanageruri = {
07083 .description = "HTML Manager Event Interface w/Digest authentication",
07084 .uri = "amanager",
07085 .has_subtree = 0,
07086 .callback = auth_manager_http_callback,
07087 .data = NULL,
07088 .key = __FILE__,
07089 };
07090
07091 static struct ast_http_uri amanagerxmluri = {
07092 .description = "XML Manager Event Interface w/Digest authentication",
07093 .uri = "amxml",
07094 .has_subtree = 0,
07095 .callback = auth_mxml_http_callback,
07096 .data = NULL,
07097 .key = __FILE__,
07098 };
07099
07100
07101 static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
07102 {
07103 struct mansession_session *session = obj;
07104 const char *login = (char *)arg;
07105 int *no_sessions = data;
07106
07107 if (strcasecmp(session->username, login) == 0) {
07108 (*no_sessions)++;
07109 }
07110
07111 return 0;
07112 }
07113
07114
07115
07116 static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07117 {
07118 struct ast_manager_user *user = NULL;
07119
07120 AST_DECLARE_APP_ARGS(args,
07121 AST_APP_ARG(name);
07122 AST_APP_ARG(param);
07123 );
07124
07125
07126 if (ast_strlen_zero(data) ) {
07127 ast_log(LOG_WARNING, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
07128 return -1;
07129 }
07130 AST_STANDARD_APP_ARGS(args, data);
07131 args.name = ast_strip(args.name);
07132 args.param = ast_strip(args.param);
07133
07134 AST_RWLIST_RDLOCK(&users);
07135 if (!(user = get_manager_by_name_locked(args.name))) {
07136 AST_RWLIST_UNLOCK(&users);
07137 ast_log(LOG_ERROR, "There's no manager user called : \"%s\"\n", args.name);
07138 return -1;
07139 }
07140 AST_RWLIST_UNLOCK(&users);
07141
07142 if (!strcasecmp(args.param, "sessions")) {
07143 int no_sessions = 0;
07144 struct ao2_container *sessions;
07145
07146 sessions = ao2_global_obj_ref(mgr_sessions);
07147 if (sessions) {
07148 ao2_callback_data(sessions, 0, get_manager_sessions_cb, data, &no_sessions);
07149 ao2_ref(sessions, -1);
07150 }
07151 snprintf(buf, len, "%d", no_sessions);
07152 } else {
07153 ast_log(LOG_ERROR, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
07154 return -1;
07155
07156 }
07157
07158 return 0;
07159 }
07160
07161
07162
07163 static struct ast_custom_function managerclient_function = {
07164 .name = "AMI_CLIENT",
07165 .read = function_amiclient,
07166 .read_max = 12,
07167 };
07168
07169 static int webregged = 0;
07170
07171
07172
07173
07174 static void purge_old_stuff(void *data)
07175 {
07176 purge_sessions(1);
07177 purge_events();
07178 }
07179
07180 static struct ast_tls_config ami_tls_cfg;
07181 static struct ast_tcptls_session_args ami_desc = {
07182 .accept_fd = -1,
07183 .master = AST_PTHREADT_NULL,
07184 .tls_cfg = NULL,
07185 .poll_timeout = 5000,
07186 .periodic_fn = purge_old_stuff,
07187 .name = "AMI server",
07188 .accept_fn = ast_tcptls_server_root,
07189 .worker_fn = session_do,
07190 };
07191
07192 static struct ast_tcptls_session_args amis_desc = {
07193 .accept_fd = -1,
07194 .master = AST_PTHREADT_NULL,
07195 .tls_cfg = &ami_tls_cfg,
07196 .poll_timeout = -1,
07197 .name = "AMI TLS server",
07198 .accept_fn = ast_tcptls_server_root,
07199 .worker_fn = session_do,
07200 };
07201
07202
07203 static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07204 {
07205 switch (cmd) {
07206 case CLI_INIT:
07207 e->command = "manager show settings";
07208 e->usage =
07209 "Usage: manager show settings\n"
07210 " Provides detailed list of the configuration of the Manager.\n";
07211 return NULL;
07212 case CLI_GENERATE:
07213 return NULL;
07214 }
07215 #define FORMAT " %-25.25s %-15.55s\n"
07216 #define FORMAT2 " %-25.25s %-15d\n"
07217 if (a->argc != 3) {
07218 return CLI_SHOWUSAGE;
07219 }
07220 ast_cli(a->fd, "\nGlobal Settings:\n");
07221 ast_cli(a->fd, "----------------\n");
07222 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
07223 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
07224 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
07225 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
07226 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
07227 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
07228 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
07229 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
07230 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
07231 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
07232 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
07233 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
07234 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
07235 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
07236 #undef FORMAT
07237 #undef FORMAT2
07238
07239 return CLI_SUCCESS;
07240 }
07241
07242 #ifdef AST_XML_DOCS
07243
07244 static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
07245 {
07246 struct ast_xml_doc_item **item_a = (struct ast_xml_doc_item **)a;
07247 struct ast_xml_doc_item **item_b = (struct ast_xml_doc_item **)b;
07248 return strcmp((*item_a)->name, (*item_b)->name);
07249 }
07250
07251 static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07252 {
07253 struct ao2_container *events;
07254 struct ao2_iterator *it_events;
07255 struct ast_xml_doc_item *item;
07256 struct ast_xml_doc_item **items;
07257 struct ast_str *buffer;
07258 int i = 0, totalitems = 0;
07259
07260 switch (cmd) {
07261 case CLI_INIT:
07262 e->command = "manager show events";
07263 e->usage =
07264 "Usage: manager show events\n"
07265 " Prints a listing of the available Asterisk manager interface events.\n";
07266 return NULL;
07267 case CLI_GENERATE:
07268 return NULL;
07269 }
07270 if (a->argc != 3) {
07271 return CLI_SHOWUSAGE;
07272 }
07273
07274 buffer = ast_str_create(128);
07275 if (!buffer) {
07276 return CLI_SUCCESS;
07277 }
07278
07279 events = ao2_global_obj_ref(event_docs);
07280 if (!events) {
07281 ast_cli(a->fd, "No manager event documentation loaded\n");
07282 ast_free(buffer);
07283 return CLI_SUCCESS;
07284 }
07285
07286 ao2_lock(events);
07287 if (!(it_events = ao2_callback(events, OBJ_MULTIPLE | OBJ_NOLOCK, NULL, NULL))) {
07288 ao2_unlock(events);
07289 ast_log(AST_LOG_ERROR, "Unable to create iterator for events container\n");
07290 ast_free(buffer);
07291 ao2_ref(events, -1);
07292 return CLI_SUCCESS;
07293 }
07294 if (!(items = ast_calloc(sizeof(struct ast_xml_doc_item *), ao2_container_count(events)))) {
07295 ao2_unlock(events);
07296 ast_log(AST_LOG_ERROR, "Unable to create temporary sorting array for events\n");
07297 ao2_iterator_destroy(it_events);
07298 ast_free(buffer);
07299 ao2_ref(events, -1);
07300 return CLI_SUCCESS;
07301 }
07302 ao2_unlock(events);
07303
07304 while ((item = ao2_iterator_next(it_events))) {
07305 items[totalitems++] = item;
07306 ao2_ref(item, -1);
07307 }
07308
07309 qsort(items, totalitems, sizeof(struct ast_xml_doc_item *), ast_xml_doc_item_cmp_fn);
07310
07311 ast_cli(a->fd, "Events:\n");
07312 ast_cli(a->fd, " -------------------- -------------------- -------------------- \n");
07313 for (i = 0; i < totalitems; i++) {
07314 ast_str_append(&buffer, 0, " %-20.20s", items[i]->name);
07315 if ((i + 1) % 3 == 0) {
07316 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
07317 ast_str_set(&buffer, 0, "%s", "");
07318 }
07319 }
07320 if ((i + 1) % 3 != 0) {
07321 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
07322 }
07323
07324 ao2_iterator_destroy(it_events);
07325 ast_free(items);
07326 ao2_ref(events, -1);
07327 ast_free(buffer);
07328
07329 return CLI_SUCCESS;
07330 }
07331
07332 static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07333 {
07334 RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup);
07335 struct ao2_iterator it_events;
07336 struct ast_xml_doc_item *item, *temp;
07337 int length;
07338 int which;
07339 char *match = NULL;
07340 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
07341
07342 if (cmd == CLI_INIT) {
07343 e->command = "manager show event";
07344 e->usage =
07345 "Usage: manager show event <eventname>\n"
07346 " Provides a detailed description a Manager interface event.\n";
07347 return NULL;
07348 }
07349
07350 events = ao2_global_obj_ref(event_docs);
07351 if (!events) {
07352 ast_cli(a->fd, "No manager event documentation loaded\n");
07353 return CLI_SUCCESS;
07354 }
07355
07356 if (cmd == CLI_GENERATE) {
07357 length = strlen(a->word);
07358 which = 0;
07359 it_events = ao2_iterator_init(events, 0);
07360 while ((item = ao2_iterator_next(&it_events))) {
07361 if (!strncasecmp(a->word, item->name, length) && ++which > a->n) {
07362 match = ast_strdup(item->name);
07363 ao2_ref(item, -1);
07364 break;
07365 }
07366 ao2_ref(item, -1);
07367 }
07368 ao2_iterator_destroy(&it_events);
07369 return match;
07370 }
07371
07372 if (a->argc != 4) {
07373 return CLI_SHOWUSAGE;
07374 }
07375
07376 if (!(item = ao2_find(events, a->argv[3], OBJ_KEY))) {
07377 ast_cli(a->fd, "Could not find event '%s'\n", a->argv[3]);
07378 return CLI_SUCCESS;
07379 }
07380
07381 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
07382 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
07383 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
07384 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
07385 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
07386
07387 ast_cli(a->fd, "Event: %s\n", a->argv[3]);
07388 for (temp = item; temp; temp = temp->next) {
07389 if (!ast_strlen_zero(ast_str_buffer(temp->synopsis))) {
07390 char *synopsis = ast_xmldoc_printable(ast_str_buffer(temp->synopsis), 1);
07391 ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
07392 ast_free(synopsis);
07393 }
07394 if (!ast_strlen_zero(ast_str_buffer(temp->syntax))) {
07395 char *syntax = ast_xmldoc_printable(ast_str_buffer(temp->syntax), 1);
07396 ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
07397 ast_free(syntax);
07398 }
07399 if (!ast_strlen_zero(ast_str_buffer(temp->description))) {
07400 char *description = ast_xmldoc_printable(ast_str_buffer(temp->description), 1);
07401 ast_cli(a->fd, "%s%s\n\n", description_title, description);
07402 ast_free(description);
07403 }
07404 if (!ast_strlen_zero(ast_str_buffer(temp->arguments))) {
07405 char *arguments = ast_xmldoc_printable(ast_str_buffer(temp->arguments), 1);
07406 ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
07407 ast_free(arguments);
07408 }
07409 if (!ast_strlen_zero(ast_str_buffer(temp->seealso))) {
07410 char *seealso = ast_xmldoc_printable(ast_str_buffer(temp->seealso), 1);
07411 ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
07412 ast_free(seealso);
07413 }
07414 }
07415
07416 ao2_ref(item, -1);
07417 return CLI_SUCCESS;
07418 }
07419
07420 #endif
07421
07422 static struct ast_cli_entry cli_manager[] = {
07423 AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
07424 AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
07425 AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
07426 AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
07427 AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
07428 AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
07429 AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
07430 AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
07431 AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
07432 #ifdef AST_XML_DOCS
07433 AST_CLI_DEFINE(handle_manager_show_events, "List manager interface events"),
07434 AST_CLI_DEFINE(handle_manager_show_event, "Show a manager interface event"),
07435 #endif
07436 };
07437
07438
07439
07440
07441
07442
07443
07444
07445
07446 static void load_channelvars(struct ast_variable *var)
07447 {
07448 struct manager_channel_variable *mcv;
07449 char *remaining = ast_strdupa(var->value);
07450 char *next;
07451
07452 ast_free(manager_channelvars);
07453 manager_channelvars = ast_strdup(var->value);
07454
07455
07456
07457
07458
07459
07460 free_channelvars();
07461 AST_RWLIST_WRLOCK(&channelvars);
07462 while ((next = strsep(&remaining, ",|"))) {
07463 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
07464 break;
07465 }
07466 strcpy(mcv->name, next);
07467 if (strchr(next, '(')) {
07468 mcv->isfunc = 1;
07469 }
07470 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
07471 }
07472 AST_RWLIST_UNLOCK(&channelvars);
07473 }
07474
07475
07476 static void manager_free_user(struct ast_manager_user *user)
07477 {
07478 ast_free(user->a1_hash);
07479 ast_free(user->secret);
07480 if (user->whitefilters) {
07481 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
07482 }
07483 if (user->blackfilters) {
07484 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
07485 }
07486 user->acl = ast_free_acl_list(user->acl);
07487 ast_variables_destroy(user->chanvars);
07488 ast_free(user);
07489 }
07490
07491
07492 static void manager_shutdown(void)
07493 {
07494 struct ast_manager_user *user;
07495
07496 ast_manager_unregister("Ping");
07497 ast_manager_unregister("Events");
07498 ast_manager_unregister("Logoff");
07499 ast_manager_unregister("Login");
07500 ast_manager_unregister("Challenge");
07501 ast_manager_unregister("Hangup");
07502 ast_manager_unregister("Status");
07503 ast_manager_unregister("Setvar");
07504 ast_manager_unregister("Getvar");
07505 ast_manager_unregister("GetConfig");
07506 ast_manager_unregister("GetConfigJSON");
07507 ast_manager_unregister("UpdateConfig");
07508 ast_manager_unregister("CreateConfig");
07509 ast_manager_unregister("ListCategories");
07510 ast_manager_unregister("Redirect");
07511 ast_manager_unregister("Atxfer");
07512 ast_manager_unregister("Originate");
07513 ast_manager_unregister("Command");
07514 ast_manager_unregister("ExtensionState");
07515 ast_manager_unregister("PresenceState");
07516 ast_manager_unregister("AbsoluteTimeout");
07517 ast_manager_unregister("MailboxStatus");
07518 ast_manager_unregister("MailboxCount");
07519 ast_manager_unregister("ListCommands");
07520 ast_manager_unregister("SendText");
07521 ast_manager_unregister("UserEvent");
07522 ast_manager_unregister("WaitEvent");
07523 ast_manager_unregister("CoreSettings");
07524 ast_manager_unregister("CoreStatus");
07525 ast_manager_unregister("Reload");
07526 ast_manager_unregister("CoreShowChannels");
07527 ast_manager_unregister("ModuleLoad");
07528 ast_manager_unregister("ModuleCheck");
07529 ast_manager_unregister("AOCMessage");
07530 ast_manager_unregister("Filter");
07531 ast_custom_function_unregister(&managerclient_function);
07532 ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
07533
07534 #ifdef AST_XML_DOCS
07535 ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
07536 #endif
07537
07538 ast_tcptls_server_stop(&ami_desc);
07539 ast_tcptls_server_stop(&amis_desc);
07540
07541 ast_free(ami_tls_cfg.certfile);
07542 ami_tls_cfg.certfile = NULL;
07543 ast_free(ami_tls_cfg.pvtfile);
07544 ami_tls_cfg.pvtfile = NULL;
07545 ast_free(ami_tls_cfg.cipher);
07546 ami_tls_cfg.cipher = NULL;
07547
07548 ao2_global_obj_release(mgr_sessions);
07549
07550 while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
07551 manager_free_user(user);
07552 }
07553 }
07554
07555 static void manager_set_defaults(void)
07556 {
07557 manager_enabled = 0;
07558 displayconnects = 1;
07559 broken_events_action = 0;
07560 authtimeout = 30;
07561 authlimit = 50;
07562 manager_debug = 0;
07563
07564
07565 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM),
07566 sizeof(global_realm));
07567 ast_sockaddr_setnull(&ami_desc.local_address);
07568 ast_sockaddr_setnull(&amis_desc.local_address);
07569
07570 ami_tls_cfg.enabled = 0;
07571 ast_free(ami_tls_cfg.certfile);
07572 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
07573 ast_free(ami_tls_cfg.pvtfile);
07574 ami_tls_cfg.pvtfile = ast_strdup("");
07575 ast_free(ami_tls_cfg.cipher);
07576 ami_tls_cfg.cipher = ast_strdup("");
07577
07578 free_channelvars();
07579 }
07580
07581 static int __init_manager(int reload, int by_external_config)
07582 {
07583 struct ast_config *ucfg = NULL, *cfg = NULL;
07584 const char *val;
07585 char *cat = NULL;
07586 int newhttptimeout = 60;
07587 struct ast_manager_user *user = NULL;
07588 struct ast_variable *var;
07589 struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
07590 char a1[256];
07591 char a1_hash[256];
07592 struct ast_sockaddr ami_desc_local_address_tmp;
07593 struct ast_sockaddr amis_desc_local_address_tmp;
07594 int tls_was_enabled = 0;
07595 int acl_subscription_flag = 0;
07596
07597 if (!reload) {
07598 struct ao2_container *sessions;
07599 #ifdef AST_XML_DOCS
07600 struct ao2_container *temp_event_docs;
07601 #endif
07602
07603 ast_register_atexit(manager_shutdown);
07604
07605
07606 ast_manager_register_xml_core("Ping", 0, action_ping);
07607 ast_manager_register_xml_core("Events", 0, action_events);
07608 ast_manager_register_xml_core("Logoff", 0, action_logoff);
07609 ast_manager_register_xml_core("Login", 0, action_login);
07610 ast_manager_register_xml_core("Challenge", 0, action_challenge);
07611 ast_manager_register_xml_core("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
07612 ast_manager_register_xml_core("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
07613 ast_manager_register_xml_core("Setvar", EVENT_FLAG_CALL, action_setvar);
07614 ast_manager_register_xml_core("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
07615 ast_manager_register_xml_core("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
07616 ast_manager_register_xml_core("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
07617 ast_manager_register_xml_core("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
07618 ast_manager_register_xml_core("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
07619 ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
07620 ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect);
07621 ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer);
07622 ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate);
07623 ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command);
07624 ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
07625 ast_manager_register_xml_core("PresenceState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_presencestate);
07626 ast_manager_register_xml_core("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
07627 ast_manager_register_xml_core("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
07628 ast_manager_register_xml_core("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
07629 ast_manager_register_xml_core("ListCommands", 0, action_listcommands);
07630 ast_manager_register_xml_core("SendText", EVENT_FLAG_CALL, action_sendtext);
07631 ast_manager_register_xml_core("UserEvent", EVENT_FLAG_USER, action_userevent);
07632 ast_manager_register_xml_core("WaitEvent", 0, action_waitevent);
07633 ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
07634 ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
07635 ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
07636 ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
07637 ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
07638 ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
07639 ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
07640 ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter);
07641
07642 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
07643 __ast_custom_function_register(&managerclient_function, NULL);
07644 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
07645
07646
07647 if (append_event("Event: Placeholder\r\n\r\n", 0)) {
07648 return -1;
07649 }
07650
07651 #ifdef AST_XML_DOCS
07652 temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
07653 if (temp_event_docs) {
07654 ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
07655 ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
07656 }
07657 #endif
07658
07659
07660 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
07661 if (!sessions) {
07662 return -1;
07663 }
07664 ao2_global_obj_replace_unref(mgr_sessions, sessions);
07665 ao2_ref(sessions, -1);
07666
07667
07668 manager_set_defaults();
07669 }
07670
07671 cfg = ast_config_load2("manager.conf", "manager", config_flags);
07672 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
07673 return 0;
07674 } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
07675 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
07676 return 0;
07677 }
07678
07679
07680 if (!by_external_config) {
07681 acl_change_event_unsubscribe();
07682 }
07683
07684 if (reload) {
07685
07686 tls_was_enabled = ami_tls_cfg.enabled;
07687 manager_set_defaults();
07688 }
07689
07690 ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
07691 ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT);
07692
07693 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
07694 val = var->value;
07695
07696
07697 if (strcasecmp(var->name, "tlscafile")
07698 && strcasecmp(var->name, "tlscapath")
07699 && strcasecmp(var->name, "tlscadir")
07700 && strcasecmp(var->name, "tlsverifyclient")
07701 && strcasecmp(var->name, "tlsdontverifyserver")
07702 && strcasecmp(var->name, "tlsclientmethod")
07703 && strcasecmp(var->name, "sslclientmethod")
07704 && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
07705 continue;
07706 }
07707
07708 if (!strcasecmp(var->name, "enabled")) {
07709 manager_enabled = ast_true(val);
07710 } else if (!strcasecmp(var->name, "webenabled")) {
07711 webmanager_enabled = ast_true(val);
07712 } else if (!strcasecmp(var->name, "port")) {
07713 int bindport;
07714 if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
07715 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
07716 }
07717 ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport);
07718 } else if (!strcasecmp(var->name, "bindaddr")) {
07719
07720 int setport = ast_sockaddr_port(&ami_desc_local_address_tmp);
07721
07722 if (ast_parse_arg(val, PARSE_ADDR|PARSE_PORT_IGNORE, NULL)) {
07723 ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", val,
07724 ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
07725 } else {
07726 ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
07727 }
07728
07729 if (setport) {
07730 ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport);
07731 }
07732
07733 } else if (!strcasecmp(var->name, "brokeneventsaction")) {
07734 broken_events_action = ast_true(val);
07735 } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
07736 allowmultiplelogin = ast_true(val);
07737 } else if (!strcasecmp(var->name, "displayconnects")) {
07738 displayconnects = ast_true(val);
07739 } else if (!strcasecmp(var->name, "timestampevents")) {
07740 timestampevents = ast_true(val);
07741 } else if (!strcasecmp(var->name, "debug")) {
07742 manager_debug = ast_true(val);
07743 } else if (!strcasecmp(var->name, "httptimeout")) {
07744 newhttptimeout = atoi(val);
07745 } else if (!strcasecmp(var->name, "authtimeout")) {
07746 int timeout = atoi(var->value);
07747
07748 if (timeout < 1) {
07749 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
07750 } else {
07751 authtimeout = timeout;
07752 }
07753 } else if (!strcasecmp(var->name, "authlimit")) {
07754 int limit = atoi(var->value);
07755
07756 if (limit < 1) {
07757 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
07758 } else {
07759 authlimit = limit;
07760 }
07761 } else if (!strcasecmp(var->name, "channelvars")) {
07762 load_channelvars(var);
07763 } else {
07764 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
07765 var->name, val);
07766 }
07767 }
07768
07769 ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
07770
07771
07772 if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
07773 ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
07774 }
07775
07776
07777
07778
07779 if (ast_sockaddr_port(&amis_desc_local_address_tmp) == 0 ||
07780 (ast_sockaddr_port(&ami_desc_local_address_tmp) == ast_sockaddr_port(&amis_desc_local_address_tmp))) {
07781
07782 ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT);
07783 }
07784
07785 if (manager_enabled) {
07786 ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
07787 ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
07788 }
07789
07790 AST_RWLIST_WRLOCK(&users);
07791
07792
07793 ucfg = ast_config_load2("users.conf", "manager", config_flags);
07794 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
07795 const char *hasmanager;
07796 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
07797
07798 while ((cat = ast_category_browse(ucfg, cat))) {
07799 if (!strcasecmp(cat, "general")) {
07800 continue;
07801 }
07802
07803 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
07804 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
07805 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
07806 const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
07807 const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
07808 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
07809 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
07810
07811
07812
07813
07814 if (!(user = get_manager_by_name_locked(cat))) {
07815 if (!(user = ast_calloc(1, sizeof(*user)))) {
07816 break;
07817 }
07818
07819
07820 ast_copy_string(user->username, cat, sizeof(user->username));
07821
07822 AST_LIST_INSERT_TAIL(&users, user, list);
07823 user->acl = NULL;
07824 user->keep = 1;
07825 user->readperm = -1;
07826 user->writeperm = -1;
07827
07828 user->displayconnects = displayconnects;
07829 user->writetimeout = 100;
07830 }
07831
07832 if (!user_secret) {
07833 user_secret = ast_variable_retrieve(ucfg, "general", "secret");
07834 }
07835 if (!user_read) {
07836 user_read = ast_variable_retrieve(ucfg, "general", "read");
07837 }
07838 if (!user_write) {
07839 user_write = ast_variable_retrieve(ucfg, "general", "write");
07840 }
07841 if (!user_displayconnects) {
07842 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
07843 }
07844 if (!user_writetimeout) {
07845 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
07846 }
07847
07848 if (!ast_strlen_zero(user_secret)) {
07849 ast_free(user->secret);
07850 user->secret = ast_strdup(user_secret);
07851 }
07852
07853 if (user_read) {
07854 user->readperm = get_perm(user_read);
07855 }
07856 if (user_write) {
07857 user->writeperm = get_perm(user_write);
07858 }
07859 if (user_displayconnects) {
07860 user->displayconnects = ast_true(user_displayconnects);
07861 }
07862 if (user_writetimeout) {
07863 int value = atoi(user_writetimeout);
07864 if (value < 100) {
07865 ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
07866 } else {
07867 user->writetimeout = value;
07868 }
07869 }
07870 }
07871 }
07872 ast_config_destroy(ucfg);
07873 }
07874
07875
07876
07877 while ((cat = ast_category_browse(cfg, cat))) {
07878 struct ast_acl_list *oldacl;
07879
07880 if (!strcasecmp(cat, "general")) {
07881 continue;
07882 }
07883
07884
07885 if (!(user = get_manager_by_name_locked(cat))) {
07886 if (!(user = ast_calloc(1, sizeof(*user)))) {
07887 break;
07888 }
07889
07890 ast_copy_string(user->username, cat, sizeof(user->username));
07891
07892 user->acl = NULL;
07893 user->readperm = 0;
07894 user->writeperm = 0;
07895
07896 user->displayconnects = displayconnects;
07897 user->writetimeout = 100;
07898 user->whitefilters = ao2_container_alloc(1, NULL, NULL);
07899 user->blackfilters = ao2_container_alloc(1, NULL, NULL);
07900 if (!user->whitefilters || !user->blackfilters) {
07901 manager_free_user(user);
07902 break;
07903 }
07904
07905
07906 AST_RWLIST_INSERT_TAIL(&users, user, list);
07907 } else {
07908 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
07909 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
07910 }
07911
07912
07913 user->keep = 1;
07914 oldacl = user->acl;
07915 user->acl = NULL;
07916 ast_variables_destroy(user->chanvars);
07917
07918 var = ast_variable_browse(cfg, cat);
07919 for (; var; var = var->next) {
07920 if (!strcasecmp(var->name, "secret")) {
07921 ast_free(user->secret);
07922 user->secret = ast_strdup(var->value);
07923 } else if (!strcasecmp(var->name, "deny") ||
07924 !strcasecmp(var->name, "permit") ||
07925 !strcasecmp(var->name, "acl")) {
07926 ast_append_acl(var->name, var->value, &user->acl, NULL, &acl_subscription_flag);
07927 } else if (!strcasecmp(var->name, "read") ) {
07928 user->readperm = get_perm(var->value);
07929 } else if (!strcasecmp(var->name, "write") ) {
07930 user->writeperm = get_perm(var->value);
07931 } else if (!strcasecmp(var->name, "displayconnects") ) {
07932 user->displayconnects = ast_true(var->value);
07933 } else if (!strcasecmp(var->name, "writetimeout")) {
07934 int value = atoi(var->value);
07935 if (value < 100) {
07936 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
07937 } else {
07938 user->writetimeout = value;
07939 }
07940 } else if (!strcasecmp(var->name, "setvar")) {
07941 struct ast_variable *tmpvar;
07942 char varbuf[256];
07943 char *varval;
07944 char *varname;
07945
07946 ast_copy_string(varbuf, var->value, sizeof(varbuf));
07947 varname = varbuf;
07948
07949 if ((varval = strchr(varname,'='))) {
07950 *varval++ = '\0';
07951 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
07952 tmpvar->next = user->chanvars;
07953 user->chanvars = tmpvar;
07954 }
07955 }
07956 } else if (!strcasecmp(var->name, "eventfilter")) {
07957 const char *value = var->value;
07958 manager_add_filter(value, user->whitefilters, user->blackfilters);
07959 } else {
07960 ast_debug(1, "%s is an unknown option.\n", var->name);
07961 }
07962 }
07963
07964 oldacl = ast_free_acl_list(oldacl);
07965 }
07966 ast_config_destroy(cfg);
07967
07968
07969 if (acl_subscription_flag && !by_external_config) {
07970 acl_change_event_subscribe();
07971 }
07972
07973
07974 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
07975 if (user->keep) {
07976 user->keep = 0;
07977
07978
07979 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
07980 ast_md5_hash(a1_hash,a1);
07981 ast_free(user->a1_hash);
07982 user->a1_hash = ast_strdup(a1_hash);
07983 continue;
07984 }
07985
07986 AST_RWLIST_REMOVE_CURRENT(list);
07987 ast_debug(4, "Pruning user '%s'\n", user->username);
07988 manager_free_user(user);
07989 }
07990 AST_RWLIST_TRAVERSE_SAFE_END;
07991
07992 AST_RWLIST_UNLOCK(&users);
07993
07994 if (webmanager_enabled && manager_enabled) {
07995 if (!webregged) {
07996 ast_http_uri_link(&rawmanuri);
07997 ast_http_uri_link(&manageruri);
07998 ast_http_uri_link(&managerxmluri);
07999
08000 ast_http_uri_link(&arawmanuri);
08001 ast_http_uri_link(&amanageruri);
08002 ast_http_uri_link(&amanagerxmluri);
08003 webregged = 1;
08004 }
08005 } else {
08006 if (webregged) {
08007 ast_http_uri_unlink(&rawmanuri);
08008 ast_http_uri_unlink(&manageruri);
08009 ast_http_uri_unlink(&managerxmluri);
08010
08011 ast_http_uri_unlink(&arawmanuri);
08012 ast_http_uri_unlink(&amanageruri);
08013 ast_http_uri_unlink(&amanagerxmluri);
08014 webregged = 0;
08015 }
08016 }
08017
08018 if (newhttptimeout > 0) {
08019 httptimeout = newhttptimeout;
08020 }
08021
08022 manager_event(EVENT_FLAG_SYSTEM, "Reload",
08023 "Module: Manager\r\n"
08024 "Status: %s\r\n"
08025 "Message: Manager reload Requested\r\n",
08026 manager_enabled ? "Enabled" : "Disabled");
08027
08028 ast_tcptls_server_start(&ami_desc);
08029 if (tls_was_enabled && !ami_tls_cfg.enabled) {
08030 ast_tcptls_server_stop(&amis_desc);
08031 } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
08032 ast_tcptls_server_start(&amis_desc);
08033 }
08034
08035 return 0;
08036 }
08037
08038 static void acl_change_event_cb(const struct ast_event *event, void *userdata)
08039 {
08040
08041 ast_log(LOG_NOTICE, "Reloading manager in response to ACL change event.\n");
08042 __init_manager(1, 1);
08043 }
08044
08045
08046 static void free_channelvars(void)
08047 {
08048 struct manager_channel_variable *var;
08049 AST_RWLIST_WRLOCK(&channelvars);
08050 while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
08051 ast_free(var);
08052 }
08053 AST_RWLIST_UNLOCK(&channelvars);
08054 }
08055
08056 int init_manager(void)
08057 {
08058 return __init_manager(0, 0);
08059 }
08060
08061 int reload_manager(void)
08062 {
08063 return __init_manager(1, 0);
08064 }
08065
08066 int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
08067 {
08068 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
08069
08070 return 0;
08071 }
08072
08073 int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
08074 {
08075 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
08076 }
08077
08078 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
08079 {
08080 struct ast_datastore *datastore = NULL;
08081
08082 if (info == NULL)
08083 return NULL;
08084
08085 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
08086 if (datastore->info != info) {
08087 continue;
08088 }
08089
08090 if (uid == NULL) {
08091
08092 break;
08093 }
08094
08095 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
08096
08097 break;
08098 }
08099 }
08100 AST_LIST_TRAVERSE_SAFE_END;
08101
08102 return datastore;
08103 }