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