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