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