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