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