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