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