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