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