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: 372845 $")
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 = NULL, *final_buf = NULL;
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 if ((fd = mkstemp(template)) < 0) {
03636 ast_log(AST_LOG_WARNING, "Failed to create temporary file for command: %s\n", strerror(errno));
03637 astman_send_error(s, m, "Command response construction error");
03638 return 0;
03639 }
03640
03641 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
03642 if (!ast_strlen_zero(id)) {
03643 astman_append(s, "ActionID: %s\r\n", id);
03644 }
03645
03646 ast_cli_command(fd, cmd);
03647
03648 if ((l = lseek(fd, 0, SEEK_END)) < 0) {
03649 ast_log(LOG_WARNING, "Failed to determine number of characters for command: %s\n", strerror(errno));
03650 goto action_command_cleanup;
03651 }
03652
03653
03654 buf = ast_malloc(l + 1);
03655 final_buf = ast_malloc(l + 1);
03656
03657 if (!buf || !final_buf) {
03658 ast_log(LOG_WARNING, "Failed to allocate memory for temporary buffer\n");
03659 goto action_command_cleanup;
03660 }
03661
03662 if (lseek(fd, 0, SEEK_SET) < 0) {
03663 ast_log(LOG_WARNING, "Failed to set position on temporary file for command: %s\n", strerror(errno));
03664 goto action_command_cleanup;
03665 }
03666
03667 if (read(fd, buf, l) < 0) {
03668 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
03669 goto action_command_cleanup;
03670 }
03671
03672 buf[l] = '\0';
03673 term_strip(final_buf, buf, l);
03674 final_buf[l] = '\0';
03675 astman_append(s, "%s", final_buf);
03676
03677 action_command_cleanup:
03678
03679 close(fd);
03680 unlink(template);
03681 astman_append(s, "--END COMMAND--\r\n\r\n");
03682
03683 ast_free(buf);
03684 ast_free(final_buf);
03685
03686 return 0;
03687 }
03688
03689
03690 struct fast_originate_helper {
03691 int timeout;
03692 format_t format;
03693 AST_DECLARE_STRING_FIELDS (
03694 AST_STRING_FIELD(tech);
03695
03696 AST_STRING_FIELD(data);
03697 AST_STRING_FIELD(app);
03698 AST_STRING_FIELD(appdata);
03699 AST_STRING_FIELD(cid_name);
03700 AST_STRING_FIELD(cid_num);
03701 AST_STRING_FIELD(context);
03702 AST_STRING_FIELD(exten);
03703 AST_STRING_FIELD(idtext);
03704 AST_STRING_FIELD(account);
03705 );
03706 int priority;
03707 struct ast_variable *vars;
03708 };
03709
03710
03711
03712
03713
03714
03715
03716
03717 static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
03718 {
03719 ast_variables_destroy(doomed->vars);
03720 ast_string_field_free_memory(doomed);
03721 ast_free(doomed);
03722 }
03723
03724 static void *fast_originate(void *data)
03725 {
03726 struct fast_originate_helper *in = data;
03727 int res;
03728 int reason = 0;
03729 struct ast_channel *chan = NULL, *chans[1];
03730 char requested_channel[AST_CHANNEL_NAME];
03731
03732 if (!ast_strlen_zero(in->app)) {
03733 res = ast_pbx_outgoing_app(in->tech, in->format, (char *) in->data,
03734 in->timeout, in->app, in->appdata, &reason, 1,
03735 S_OR(in->cid_num, NULL),
03736 S_OR(in->cid_name, NULL),
03737 in->vars, in->account, &chan);
03738 } else {
03739 res = ast_pbx_outgoing_exten(in->tech, in->format, (char *) in->data,
03740 in->timeout, in->context, in->exten, in->priority, &reason, 1,
03741 S_OR(in->cid_num, NULL),
03742 S_OR(in->cid_name, NULL),
03743 in->vars, in->account, &chan);
03744 }
03745
03746 in->vars = NULL;
03747
03748 if (!chan) {
03749 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
03750 }
03751
03752 chans[0] = chan;
03753 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
03754 "%s"
03755 "Response: %s\r\n"
03756 "Channel: %s\r\n"
03757 "Context: %s\r\n"
03758 "Exten: %s\r\n"
03759 "Reason: %d\r\n"
03760 "Uniqueid: %s\r\n"
03761 "CallerIDNum: %s\r\n"
03762 "CallerIDName: %s\r\n",
03763 in->idtext, res ? "Failure" : "Success",
03764 chan ? chan->name : requested_channel, in->context, in->exten, reason,
03765 chan ? chan->uniqueid : "<null>",
03766 S_OR(in->cid_num, "<unknown>"),
03767 S_OR(in->cid_name, "<unknown>")
03768 );
03769
03770
03771 if (chan) {
03772 ast_channel_unlock(chan);
03773 }
03774 destroy_fast_originate_helper(in);
03775 return NULL;
03776 }
03777
03778 static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
03779 {
03780 const char *unitamount;
03781 const char *unittype;
03782 struct ast_str *str = ast_str_alloca(32);
03783
03784 memset(entry, 0, sizeof(*entry));
03785
03786 ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
03787 unitamount = astman_get_header(m, ast_str_buffer(str));
03788
03789 ast_str_set(&str, 0, "UnitType(%u)", entry_num);
03790 unittype = astman_get_header(m, ast_str_buffer(str));
03791
03792 if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
03793 entry->valid_amount = 1;
03794 }
03795
03796 if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
03797 entry->valid_type = 1;
03798 }
03799
03800 return 0;
03801 }
03802
03803 static int action_aocmessage(struct mansession *s, const struct message *m)
03804 {
03805 const char *channel = astman_get_header(m, "Channel");
03806 const char *pchannel = astman_get_header(m, "ChannelPrefix");
03807 const char *msgtype = astman_get_header(m, "MsgType");
03808 const char *chargetype = astman_get_header(m, "ChargeType");
03809 const char *currencyname = astman_get_header(m, "CurrencyName");
03810 const char *currencyamount = astman_get_header(m, "CurrencyAmount");
03811 const char *mult = astman_get_header(m, "CurrencyMultiplier");
03812 const char *totaltype = astman_get_header(m, "TotalType");
03813 const char *aocbillingid = astman_get_header(m, "AOCBillingId");
03814 const char *association_id= astman_get_header(m, "ChargingAssociationId");
03815 const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
03816 const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
03817
03818 enum ast_aoc_type _msgtype;
03819 enum ast_aoc_charge_type _chargetype;
03820 enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
03821 enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
03822 enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
03823 unsigned int _currencyamount = 0;
03824 int _association_id = 0;
03825 unsigned int _association_plan = 0;
03826 struct ast_channel *chan = NULL;
03827
03828 struct ast_aoc_decoded *decoded = NULL;
03829 struct ast_aoc_encoded *encoded = NULL;
03830 size_t encoded_size = 0;
03831
03832 if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
03833 astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
03834 goto aocmessage_cleanup;
03835 }
03836
03837 if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
03838 chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
03839 }
03840
03841 if (!chan) {
03842 astman_send_error(s, m, "No such channel");
03843 goto aocmessage_cleanup;
03844 }
03845
03846 if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
03847 astman_send_error(s, m, "Invalid MsgType");
03848 goto aocmessage_cleanup;
03849 }
03850
03851 if (ast_strlen_zero(chargetype)) {
03852 astman_send_error(s, m, "ChargeType not specified");
03853 goto aocmessage_cleanup;
03854 }
03855
03856 _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
03857
03858 if (!strcasecmp(chargetype, "NA")) {
03859 _chargetype = AST_AOC_CHARGE_NA;
03860 } else if (!strcasecmp(chargetype, "Free")) {
03861 _chargetype = AST_AOC_CHARGE_FREE;
03862 } else if (!strcasecmp(chargetype, "Currency")) {
03863 _chargetype = AST_AOC_CHARGE_CURRENCY;
03864 } else if (!strcasecmp(chargetype, "Unit")) {
03865 _chargetype = AST_AOC_CHARGE_UNIT;
03866 } else {
03867 astman_send_error(s, m, "Invalid ChargeType");
03868 goto aocmessage_cleanup;
03869 }
03870
03871 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
03872
03873 if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
03874 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
03875 goto aocmessage_cleanup;
03876 }
03877
03878 if (ast_strlen_zero(mult)) {
03879 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
03880 goto aocmessage_cleanup;
03881 } else if (!strcasecmp(mult, "onethousandth")) {
03882 _mult = AST_AOC_MULT_ONETHOUSANDTH;
03883 } else if (!strcasecmp(mult, "onehundredth")) {
03884 _mult = AST_AOC_MULT_ONEHUNDREDTH;
03885 } else if (!strcasecmp(mult, "onetenth")) {
03886 _mult = AST_AOC_MULT_ONETENTH;
03887 } else if (!strcasecmp(mult, "one")) {
03888 _mult = AST_AOC_MULT_ONE;
03889 } else if (!strcasecmp(mult, "ten")) {
03890 _mult = AST_AOC_MULT_TEN;
03891 } else if (!strcasecmp(mult, "hundred")) {
03892 _mult = AST_AOC_MULT_HUNDRED;
03893 } else if (!strcasecmp(mult, "thousand")) {
03894 _mult = AST_AOC_MULT_THOUSAND;
03895 } else {
03896 astman_send_error(s, m, "Invalid ChargeMultiplier");
03897 goto aocmessage_cleanup;
03898 }
03899 }
03900
03901
03902 if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
03903 astman_send_error(s, m, "Message Creation Failed");
03904 goto aocmessage_cleanup;
03905 }
03906
03907 if (_msgtype == AST_AOC_D) {
03908 if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
03909 _totaltype = AST_AOC_SUBTOTAL;
03910 }
03911
03912 if (ast_strlen_zero(aocbillingid)) {
03913
03914 } else if (!strcasecmp(aocbillingid, "Normal")) {
03915 _billingid = AST_AOC_BILLING_NORMAL;
03916 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
03917 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
03918 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
03919 _billingid = AST_AOC_BILLING_CREDIT_CARD;
03920 } else {
03921 astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
03922 goto aocmessage_cleanup;
03923 }
03924 } else {
03925 if (ast_strlen_zero(aocbillingid)) {
03926
03927 } else if (!strcasecmp(aocbillingid, "Normal")) {
03928 _billingid = AST_AOC_BILLING_NORMAL;
03929 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
03930 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
03931 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
03932 _billingid = AST_AOC_BILLING_CREDIT_CARD;
03933 } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
03934 _billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL;
03935 } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
03936 _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
03937 } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
03938 _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
03939 } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
03940 _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
03941 } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
03942 _billingid = AST_AOC_BILLING_CALL_TRANSFER;
03943 } else {
03944 astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
03945 goto aocmessage_cleanup;
03946 }
03947
03948 if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
03949 astman_send_error(s, m, "Invalid ChargingAssociationId");
03950 goto aocmessage_cleanup;
03951 }
03952 if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
03953 astman_send_error(s, m, "Invalid ChargingAssociationPlan");
03954 goto aocmessage_cleanup;
03955 }
03956
03957 if (_association_id) {
03958 ast_aoc_set_association_id(decoded, _association_id);
03959 } else if (!ast_strlen_zero(association_num)) {
03960 ast_aoc_set_association_number(decoded, association_num, _association_plan);
03961 }
03962 }
03963
03964 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
03965 ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
03966 } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
03967 struct ast_aoc_unit_entry entry;
03968 int i;
03969
03970
03971 for (i = 0; i < 32; i++) {
03972 if (aocmessage_get_unit_entry(m, &entry, i)) {
03973 break;
03974 }
03975
03976 ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
03977 }
03978
03979
03980 if (!i) {
03981 astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
03982 goto aocmessage_cleanup;
03983 }
03984
03985 }
03986
03987 ast_aoc_set_billing_id(decoded, _billingid);
03988 ast_aoc_set_total_type(decoded, _totaltype);
03989
03990
03991 if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
03992 astman_send_ack(s, m, "AOC Message successfully queued on channel");
03993 } else {
03994 astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
03995 }
03996
03997 aocmessage_cleanup:
03998
03999 ast_aoc_destroy_decoded(decoded);
04000 ast_aoc_destroy_encoded(encoded);
04001
04002 if (chan) {
04003 chan = ast_channel_unref(chan);
04004 }
04005 return 0;
04006 }
04007
04008 static int action_originate(struct mansession *s, const struct message *m)
04009 {
04010 const char *name = astman_get_header(m, "Channel");
04011 const char *exten = astman_get_header(m, "Exten");
04012 const char *context = astman_get_header(m, "Context");
04013 const char *priority = astman_get_header(m, "Priority");
04014 const char *timeout = astman_get_header(m, "Timeout");
04015 const char *callerid = astman_get_header(m, "CallerID");
04016 const char *account = astman_get_header(m, "Account");
04017 const char *app = astman_get_header(m, "Application");
04018 const char *appdata = astman_get_header(m, "Data");
04019 const char *async = astman_get_header(m, "Async");
04020 const char *id = astman_get_header(m, "ActionID");
04021 const char *codecs = astman_get_header(m, "Codecs");
04022 struct ast_variable *vars;
04023 char *tech, *data;
04024 char *l = NULL, *n = NULL;
04025 int pi = 0;
04026 int res;
04027 int to = 30000;
04028 int reason = 0;
04029 char tmp[256];
04030 char tmp2[256];
04031 format_t format = AST_FORMAT_SLINEAR;
04032
04033 pthread_t th;
04034 if (ast_strlen_zero(name)) {
04035 astman_send_error(s, m, "Channel not specified");
04036 return 0;
04037 }
04038 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
04039 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
04040 astman_send_error(s, m, "Invalid priority");
04041 return 0;
04042 }
04043 }
04044 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
04045 astman_send_error(s, m, "Invalid timeout");
04046 return 0;
04047 }
04048 ast_copy_string(tmp, name, sizeof(tmp));
04049 tech = tmp;
04050 data = strchr(tmp, '/');
04051 if (!data) {
04052 astman_send_error(s, m, "Invalid channel");
04053 return 0;
04054 }
04055 *data++ = '\0';
04056 ast_copy_string(tmp2, callerid, sizeof(tmp2));
04057 ast_callerid_parse(tmp2, &n, &l);
04058 if (n) {
04059 if (ast_strlen_zero(n)) {
04060 n = NULL;
04061 }
04062 }
04063 if (l) {
04064 ast_shrink_phone_number(l);
04065 if (ast_strlen_zero(l)) {
04066 l = NULL;
04067 }
04068 }
04069 if (!ast_strlen_zero(codecs)) {
04070 format = 0;
04071 ast_parse_allow_disallow(NULL, &format, codecs, 1);
04072 }
04073 if (!ast_strlen_zero(app) && s->session) {
04074 int bad_appdata = 0;
04075
04076
04077 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
04078 && (
04079 strcasestr(app, "system") ||
04080
04081 strcasestr(app, "exec") ||
04082
04083 strcasestr(app, "agi") ||
04084
04085 strcasestr(app, "mixmonitor") ||
04086 strcasestr(app, "externalivr") ||
04087 (strstr(appdata, "SHELL") && (bad_appdata = 1)) ||
04088 (strstr(appdata, "EVAL") && (bad_appdata = 1))
04089 )) {
04090 char error_buf[64];
04091 snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
04092 astman_send_error(s, m, error_buf);
04093 return 0;
04094 }
04095 }
04096
04097 vars = astman_get_variables(m);
04098
04099 if (ast_true(async)) {
04100 struct fast_originate_helper *fast;
04101
04102 fast = ast_calloc(1, sizeof(*fast));
04103 if (!fast || ast_string_field_init(fast, 252)) {
04104 ast_free(fast);
04105 ast_variables_destroy(vars);
04106 res = -1;
04107 } else {
04108 if (!ast_strlen_zero(id)) {
04109 ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id);
04110 }
04111 ast_string_field_set(fast, tech, tech);
04112 ast_string_field_set(fast, data, data);
04113 ast_string_field_set(fast, app, app);
04114 ast_string_field_set(fast, appdata, appdata);
04115 ast_string_field_set(fast, cid_num, l);
04116 ast_string_field_set(fast, cid_name, n);
04117 ast_string_field_set(fast, context, context);
04118 ast_string_field_set(fast, exten, exten);
04119 ast_string_field_set(fast, account, account);
04120 fast->vars = vars;
04121 fast->format = format;
04122 fast->timeout = to;
04123 fast->priority = pi;
04124 if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
04125 destroy_fast_originate_helper(fast);
04126 res = -1;
04127 } else {
04128 res = 0;
04129 }
04130 }
04131 } else if (!ast_strlen_zero(app)) {
04132 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
04133
04134 } else {
04135 if (exten && context && pi) {
04136 res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
04137
04138 } else {
04139 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
04140 ast_variables_destroy(vars);
04141 return 0;
04142 }
04143 }
04144 if (!res) {
04145 astman_send_ack(s, m, "Originate successfully queued");
04146 } else {
04147 astman_send_error(s, m, "Originate failed");
04148 }
04149 return 0;
04150 }
04151
04152 static int action_mailboxstatus(struct mansession *s, const struct message *m)
04153 {
04154 const char *mailbox = astman_get_header(m, "Mailbox");
04155 int ret;
04156
04157 if (ast_strlen_zero(mailbox)) {
04158 astman_send_error(s, m, "Mailbox not specified");
04159 return 0;
04160 }
04161 ret = ast_app_has_voicemail(mailbox, NULL);
04162 astman_start_ack(s, m);
04163 astman_append(s, "Message: Mailbox Status\r\n"
04164 "Mailbox: %s\r\n"
04165 "Waiting: %d\r\n\r\n", mailbox, ret);
04166 return 0;
04167 }
04168
04169 static int action_mailboxcount(struct mansession *s, const struct message *m)
04170 {
04171 const char *mailbox = astman_get_header(m, "Mailbox");
04172 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
04173
04174 if (ast_strlen_zero(mailbox)) {
04175 astman_send_error(s, m, "Mailbox not specified");
04176 return 0;
04177 }
04178 ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
04179 astman_start_ack(s, m);
04180 astman_append(s, "Message: Mailbox Message Count\r\n"
04181 "Mailbox: %s\r\n"
04182 "UrgMessages: %d\r\n"
04183 "NewMessages: %d\r\n"
04184 "OldMessages: %d\r\n"
04185 "\r\n",
04186 mailbox, urgentmsgs, newmsgs, oldmsgs);
04187 return 0;
04188 }
04189
04190 static int action_extensionstate(struct mansession *s, const struct message *m)
04191 {
04192 const char *exten = astman_get_header(m, "Exten");
04193 const char *context = astman_get_header(m, "Context");
04194 char hint[256] = "";
04195 int status;
04196 if (ast_strlen_zero(exten)) {
04197 astman_send_error(s, m, "Extension not specified");
04198 return 0;
04199 }
04200 if (ast_strlen_zero(context)) {
04201 context = "default";
04202 }
04203 status = ast_extension_state(NULL, context, exten);
04204 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
04205 astman_start_ack(s, m);
04206 astman_append(s, "Message: Extension Status\r\n"
04207 "Exten: %s\r\n"
04208 "Context: %s\r\n"
04209 "Hint: %s\r\n"
04210 "Status: %d\r\n\r\n",
04211 exten, context, hint, status);
04212 return 0;
04213 }
04214
04215 static int action_timeout(struct mansession *s, const struct message *m)
04216 {
04217 struct ast_channel *c;
04218 const char *name = astman_get_header(m, "Channel");
04219 double timeout = atof(astman_get_header(m, "Timeout"));
04220 struct timeval when = { timeout, 0 };
04221
04222 if (ast_strlen_zero(name)) {
04223 astman_send_error(s, m, "No channel specified");
04224 return 0;
04225 }
04226
04227 if (!timeout || timeout < 0) {
04228 astman_send_error(s, m, "No timeout specified");
04229 return 0;
04230 }
04231
04232 if (!(c = ast_channel_get_by_name(name))) {
04233 astman_send_error(s, m, "No such channel");
04234 return 0;
04235 }
04236
04237 when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
04238
04239 ast_channel_lock(c);
04240 ast_channel_setwhentohangup_tv(c, when);
04241 ast_channel_unlock(c);
04242 c = ast_channel_unref(c);
04243
04244 astman_send_ack(s, m, "Timeout Set");
04245
04246 return 0;
04247 }
04248
04249 static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04250 {
04251 regex_t *regex_filter = obj;
04252 const char *eventdata = arg;
04253 int *result = data;
04254
04255 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
04256 *result = 1;
04257 return (CMP_MATCH | CMP_STOP);
04258 }
04259
04260 return 0;
04261 }
04262
04263 static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
04264 {
04265 regex_t *regex_filter = obj;
04266 const char *eventdata = arg;
04267 int *result = data;
04268
04269 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
04270 *result = 0;
04271 return (CMP_MATCH | CMP_STOP);
04272 }
04273
04274 *result = 1;
04275 return 0;
04276 }
04277
04278 static int match_filter(struct mansession *s, char *eventdata)
04279 {
04280 int result = 0;
04281
04282 ast_debug(3, "Examining event:\n%s\n", eventdata);
04283 if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04284 return 1;
04285 } else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
04286
04287 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04288 } else if (!ao2_container_count(s->session->whitefilters) && ao2_container_count(s->session->blackfilters)) {
04289
04290 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04291 } else {
04292
04293 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04294 if (result) {
04295 result = 0;
04296 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
04297 }
04298 }
04299
04300 return result;
04301 }
04302
04303
04304
04305
04306
04307
04308 static int process_events(struct mansession *s)
04309 {
04310 int ret = 0;
04311
04312 ao2_lock(s->session);
04313 if (s->session->f != NULL) {
04314 struct eventqent *eqe = s->session->last_ev;
04315
04316 while ((eqe = advance_event(eqe))) {
04317 if (!ret && s->session->authenticated &&
04318 (s->session->readperm & eqe->category) == eqe->category &&
04319 (s->session->send_events & eqe->category) == eqe->category) {
04320 if (match_filter(s, eqe->eventdata)) {
04321 if (send_string(s, eqe->eventdata) < 0)
04322 ret = -1;
04323 }
04324 }
04325 s->session->last_ev = eqe;
04326 }
04327 }
04328 ao2_unlock(s->session);
04329 return ret;
04330 }
04331
04332 static int action_userevent(struct mansession *s, const struct message *m)
04333 {
04334 const char *event = astman_get_header(m, "UserEvent");
04335 struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
04336 int x;
04337
04338 ast_str_reset(body);
04339
04340 for (x = 0; x < m->hdrcount; x++) {
04341 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
04342 ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
04343 }
04344 }
04345
04346 astman_send_ack(s, m, "Event Sent");
04347 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
04348 return 0;
04349 }
04350
04351
04352 static int action_coresettings(struct mansession *s, const struct message *m)
04353 {
04354 const char *actionid = astman_get_header(m, "ActionID");
04355 char idText[150];
04356
04357 if (!ast_strlen_zero(actionid)) {
04358 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04359 } else {
04360 idText[0] = '\0';
04361 }
04362
04363 astman_append(s, "Response: Success\r\n"
04364 "%s"
04365 "AMIversion: %s\r\n"
04366 "AsteriskVersion: %s\r\n"
04367 "SystemName: %s\r\n"
04368 "CoreMaxCalls: %d\r\n"
04369 "CoreMaxLoadAvg: %f\r\n"
04370 "CoreRunUser: %s\r\n"
04371 "CoreRunGroup: %s\r\n"
04372 "CoreMaxFilehandles: %d\r\n"
04373 "CoreRealTimeEnabled: %s\r\n"
04374 "CoreCDRenabled: %s\r\n"
04375 "CoreHTTPenabled: %s\r\n"
04376 "\r\n",
04377 idText,
04378 AMI_VERSION,
04379 ast_get_version(),
04380 ast_config_AST_SYSTEM_NAME,
04381 option_maxcalls,
04382 option_maxload,
04383 ast_config_AST_RUN_USER,
04384 ast_config_AST_RUN_GROUP,
04385 option_maxfiles,
04386 AST_CLI_YESNO(ast_realtime_enabled()),
04387 AST_CLI_YESNO(check_cdr_enabled()),
04388 AST_CLI_YESNO(check_webmanager_enabled())
04389 );
04390 return 0;
04391 }
04392
04393
04394 static int action_corestatus(struct mansession *s, const struct message *m)
04395 {
04396 const char *actionid = astman_get_header(m, "ActionID");
04397 char idText[150];
04398 char startuptime[150], startupdate[150];
04399 char reloadtime[150], reloaddate[150];
04400 struct ast_tm tm;
04401
04402 if (!ast_strlen_zero(actionid)) {
04403 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04404 } else {
04405 idText[0] = '\0';
04406 }
04407
04408 ast_localtime(&ast_startuptime, &tm, NULL);
04409 ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
04410 ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
04411 ast_localtime(&ast_lastreloadtime, &tm, NULL);
04412 ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
04413 ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
04414
04415 astman_append(s, "Response: Success\r\n"
04416 "%s"
04417 "CoreStartupDate: %s\r\n"
04418 "CoreStartupTime: %s\r\n"
04419 "CoreReloadDate: %s\r\n"
04420 "CoreReloadTime: %s\r\n"
04421 "CoreCurrentCalls: %d\r\n"
04422 "\r\n",
04423 idText,
04424 startupdate,
04425 startuptime,
04426 reloaddate,
04427 reloadtime,
04428 ast_active_channels()
04429 );
04430 return 0;
04431 }
04432
04433
04434 static int action_reload(struct mansession *s, const struct message *m)
04435 {
04436 const char *module = astman_get_header(m, "Module");
04437 int res = ast_module_reload(S_OR(module, NULL));
04438
04439 switch (res) {
04440 case -1:
04441 astman_send_error(s, m, "A reload is in progress");
04442 break;
04443 case 0:
04444 astman_send_error(s, m, "No such module");
04445 break;
04446 case 1:
04447 astman_send_error(s, m, "Module does not support reload");
04448 break;
04449 case 2:
04450 astman_send_ack(s, m, "Module Reloaded");
04451 break;
04452 default:
04453 astman_send_error(s, m, "An unknown error occurred");
04454 break;
04455 }
04456 return 0;
04457 }
04458
04459
04460
04461 static int action_coreshowchannels(struct mansession *s, const struct message *m)
04462 {
04463 const char *actionid = astman_get_header(m, "ActionID");
04464 char idText[256];
04465 struct ast_channel *c = NULL;
04466 int numchans = 0;
04467 int duration, durh, durm, durs;
04468 struct ast_channel_iterator *iter;
04469
04470 if (!ast_strlen_zero(actionid)) {
04471 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04472 } else {
04473 idText[0] = '\0';
04474 }
04475
04476 if (!(iter = ast_channel_iterator_all_new())) {
04477 astman_send_error(s, m, "Memory Allocation Failure");
04478 return 1;
04479 }
04480
04481 astman_send_listack(s, m, "Channels will follow", "start");
04482
04483 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
04484 struct ast_channel *bc;
04485 char durbuf[10] = "";
04486
04487 ast_channel_lock(c);
04488
04489 bc = ast_bridged_channel(c);
04490 if (c->cdr && !ast_tvzero(c->cdr->start)) {
04491 duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
04492 durh = duration / 3600;
04493 durm = (duration % 3600) / 60;
04494 durs = duration % 60;
04495 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
04496 }
04497
04498 astman_append(s,
04499 "Event: CoreShowChannel\r\n"
04500 "%s"
04501 "Channel: %s\r\n"
04502 "UniqueID: %s\r\n"
04503 "Context: %s\r\n"
04504 "Extension: %s\r\n"
04505 "Priority: %d\r\n"
04506 "ChannelState: %d\r\n"
04507 "ChannelStateDesc: %s\r\n"
04508 "Application: %s\r\n"
04509 "ApplicationData: %s\r\n"
04510 "CallerIDnum: %s\r\n"
04511 "CallerIDname: %s\r\n"
04512 "ConnectedLineNum: %s\r\n"
04513 "ConnectedLineName: %s\r\n"
04514 "Duration: %s\r\n"
04515 "AccountCode: %s\r\n"
04516 "BridgedChannel: %s\r\n"
04517 "BridgedUniqueID: %s\r\n"
04518 "\r\n", idText, c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state,
04519 ast_state2str(c->_state), c->appl ? c->appl : "", c->data ? S_OR(c->data, "") : "",
04520 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
04521 S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
04522 S_COR(c->connected.id.number.valid, c->connected.id.number.str, ""),
04523 S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
04524 durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
04525
04526 ast_channel_unlock(c);
04527
04528 numchans++;
04529 }
04530
04531 astman_append(s,
04532 "Event: CoreShowChannelsComplete\r\n"
04533 "EventList: Complete\r\n"
04534 "ListItems: %d\r\n"
04535 "%s"
04536 "\r\n", numchans, idText);
04537
04538 ast_channel_iterator_destroy(iter);
04539
04540 return 0;
04541 }
04542
04543
04544 static int manager_modulecheck(struct mansession *s, const struct message *m)
04545 {
04546 int res;
04547 const char *module = astman_get_header(m, "Module");
04548 const char *id = astman_get_header(m, "ActionID");
04549 char idText[256];
04550 #if !defined(LOW_MEMORY)
04551 const char *version;
04552 #endif
04553 char filename[PATH_MAX];
04554 char *cut;
04555
04556 ast_copy_string(filename, module, sizeof(filename));
04557 if ((cut = strchr(filename, '.'))) {
04558 *cut = '\0';
04559 } else {
04560 cut = filename + strlen(filename);
04561 }
04562 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
04563 ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
04564 res = ast_module_check(filename);
04565 if (!res) {
04566 astman_send_error(s, m, "Module not loaded");
04567 return 0;
04568 }
04569 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
04570 ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
04571 #if !defined(LOW_MEMORY)
04572 version = ast_file_version_find(filename);
04573 #endif
04574
04575 if (!ast_strlen_zero(id)) {
04576 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04577 } else {
04578 idText[0] = '\0';
04579 }
04580 astman_append(s, "Response: Success\r\n%s", idText);
04581 #if !defined(LOW_MEMORY)
04582 astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
04583 #endif
04584 return 0;
04585 }
04586
04587 static int manager_moduleload(struct mansession *s, const struct message *m)
04588 {
04589 int res;
04590 const char *module = astman_get_header(m, "Module");
04591 const char *loadtype = astman_get_header(m, "LoadType");
04592
04593 if (!loadtype || strlen(loadtype) == 0) {
04594 astman_send_error(s, m, "Incomplete ModuleLoad action.");
04595 }
04596 if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
04597 astman_send_error(s, m, "Need module name");
04598 }
04599
04600 if (!strcasecmp(loadtype, "load")) {
04601 res = ast_load_resource(module);
04602 if (res) {
04603 astman_send_error(s, m, "Could not load module.");
04604 } else {
04605 astman_send_ack(s, m, "Module loaded.");
04606 }
04607 } else if (!strcasecmp(loadtype, "unload")) {
04608 res = ast_unload_resource(module, AST_FORCE_SOFT);
04609 if (res) {
04610 astman_send_error(s, m, "Could not unload module.");
04611 } else {
04612 astman_send_ack(s, m, "Module unloaded.");
04613 }
04614 } else if (!strcasecmp(loadtype, "reload")) {
04615 if (!ast_strlen_zero(module)) {
04616 res = ast_module_reload(module);
04617 if (res == 0) {
04618 astman_send_error(s, m, "No such module.");
04619 } else if (res == 1) {
04620 astman_send_error(s, m, "Module does not support reload action.");
04621 } else {
04622 astman_send_ack(s, m, "Module reloaded.");
04623 }
04624 } else {
04625 ast_module_reload(NULL);
04626 astman_send_ack(s, m, "All modules reloaded");
04627 }
04628 } else
04629 astman_send_error(s, m, "Incomplete ModuleLoad action.");
04630 return 0;
04631 }
04632
04633
04634
04635
04636
04637
04638
04639
04640
04641
04642
04643
04644
04645
04646 static int process_message(struct mansession *s, const struct message *m)
04647 {
04648 int ret = 0;
04649 struct manager_action *act_found;
04650 const char *user;
04651 const char *action;
04652
04653 action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
04654 if (ast_strlen_zero(action)) {
04655 report_req_bad_format(s, "NONE");
04656 mansession_lock(s);
04657 astman_send_error(s, m, "Missing action in request");
04658 mansession_unlock(s);
04659 return 0;
04660 }
04661
04662 if (!s->session->authenticated
04663 && strcasecmp(action, "Login")
04664 && strcasecmp(action, "Logoff")
04665 && strcasecmp(action, "Challenge")) {
04666 if (!s->session->authenticated) {
04667 report_req_not_allowed(s, action);
04668 }
04669 mansession_lock(s);
04670 astman_send_error(s, m, "Permission denied");
04671 mansession_unlock(s);
04672 return 0;
04673 }
04674
04675 if (!allowmultiplelogin
04676 && !s->session->authenticated
04677 && (!strcasecmp(action, "Login")
04678 || !strcasecmp(action, "Challenge"))) {
04679 user = astman_get_header(m, "Username");
04680
04681 if (check_manager_session_inuse(user)) {
04682 report_session_limit(s);
04683 sleep(1);
04684 mansession_lock(s);
04685 astman_send_error(s, m, "Login Already In Use");
04686 mansession_unlock(s);
04687 return -1;
04688 }
04689 }
04690
04691 act_found = action_find(action);
04692 if (act_found) {
04693
04694 int acted = 0;
04695
04696 if ((s->session->writeperm & act_found->authority)
04697 || act_found->authority == 0) {
04698
04699 ao2_lock(act_found);
04700 if (act_found->registered && act_found->func) {
04701 ast_debug(1, "Running action '%s'\n", act_found->action);
04702 ++act_found->active_count;
04703 ao2_unlock(act_found);
04704 ret = act_found->func(s, m);
04705 acted = 1;
04706 ao2_lock(act_found);
04707 --act_found->active_count;
04708 }
04709 ao2_unlock(act_found);
04710 }
04711 if (!acted) {
04712
04713
04714
04715
04716
04717 report_req_not_allowed(s, action);
04718 mansession_lock(s);
04719 astman_send_error(s, m, "Permission denied");
04720 mansession_unlock(s);
04721 }
04722 ao2_t_ref(act_found, -1, "done with found action object");
04723 } else {
04724 char buf[512];
04725
04726 report_req_bad_format(s, action);
04727 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
04728 mansession_lock(s);
04729 astman_send_error(s, m, buf);
04730 mansession_unlock(s);
04731 }
04732 if (ret) {
04733 return ret;
04734 }
04735
04736
04737
04738 if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
04739 return process_events(s);
04740 } else {
04741 return ret;
04742 }
04743 }
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754 static int get_input(struct mansession *s, char *output)
04755 {
04756 int res, x;
04757 int maxlen = sizeof(s->session->inbuf) - 1;
04758 char *src = s->session->inbuf;
04759 int timeout = -1;
04760 time_t now;
04761
04762
04763
04764
04765
04766 for (x = 0; x < s->session->inlen; x++) {
04767 int cr;
04768 if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
04769 cr = 2;
04770 } else if (src[x] == '\n') {
04771 cr = 1;
04772 } else {
04773 continue;
04774 }
04775 memmove(output, src, x);
04776 output[x] = '\0';
04777 x += cr;
04778 s->session->inlen -= x;
04779 memmove(src, src + x, s->session->inlen);
04780 return 1;
04781 }
04782 if (s->session->inlen >= maxlen) {
04783
04784 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->session->sin.sin_addr), src);
04785 s->session->inlen = 0;
04786 }
04787 res = 0;
04788 while (res == 0) {
04789
04790 if (!s->session->authenticated) {
04791 if(time(&now) == -1) {
04792 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
04793 return -1;
04794 }
04795
04796 timeout = (authtimeout - (now - s->session->authstart)) * 1000;
04797 if (timeout < 0) {
04798
04799 return 0;
04800 }
04801 }
04802
04803 ao2_lock(s->session);
04804 if (s->session->pending_event) {
04805 s->session->pending_event = 0;
04806 ao2_unlock(s->session);
04807 return 0;
04808 }
04809 s->session->waiting_thread = pthread_self();
04810 ao2_unlock(s->session);
04811
04812 res = ast_wait_for_input(s->session->fd, timeout);
04813
04814 ao2_lock(s->session);
04815 s->session->waiting_thread = AST_PTHREADT_NULL;
04816 ao2_unlock(s->session);
04817 }
04818 if (res < 0) {
04819
04820
04821
04822 if (errno == EINTR || errno == EAGAIN) {
04823 return 0;
04824 }
04825 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
04826 return -1;
04827 }
04828
04829 ao2_lock(s->session);
04830 res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
04831 if (res < 1) {
04832 res = -1;
04833 } else {
04834 s->session->inlen += res;
04835 src[s->session->inlen] = '\0';
04836 res = 0;
04837 }
04838 ao2_unlock(s->session);
04839 return res;
04840 }
04841
04842
04843
04844
04845
04846
04847
04848
04849
04850
04851 static int do_message(struct mansession *s)
04852 {
04853 struct message m = { 0 };
04854 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
04855 int res;
04856 int idx;
04857 int hdr_loss;
04858 time_t now;
04859
04860 hdr_loss = 0;
04861 for (;;) {
04862
04863 if (process_events(s)) {
04864 res = -1;
04865 break;
04866 }
04867 res = get_input(s, header_buf);
04868 if (res == 0) {
04869
04870 if (!s->session->authenticated) {
04871 if (time(&now) == -1) {
04872 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
04873 res = -1;
04874 break;
04875 }
04876
04877 if (now - s->session->authstart > authtimeout) {
04878 if (displayconnects) {
04879 ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_inet_ntoa(s->session->sin.sin_addr), authtimeout);
04880 }
04881 res = -1;
04882 break;
04883 }
04884 }
04885 continue;
04886 } else if (res > 0) {
04887
04888 if (ast_strlen_zero(header_buf)) {
04889 if (hdr_loss) {
04890 mansession_lock(s);
04891 astman_send_error(s, &m, "Too many lines in message or allocation failure");
04892 mansession_unlock(s);
04893 res = 0;
04894 } else {
04895 res = process_message(s, &m) ? -1 : 0;
04896 }
04897 break;
04898 } else if (m.hdrcount < ARRAY_LEN(m.headers)) {
04899 m.headers[m.hdrcount] = ast_strdup(header_buf);
04900 if (!m.headers[m.hdrcount]) {
04901
04902 hdr_loss = 1;
04903 } else {
04904 ++m.hdrcount;
04905 }
04906 } else {
04907
04908 hdr_loss = 1;
04909 }
04910 } else {
04911
04912 break;
04913 }
04914 }
04915
04916
04917 for (idx = 0; idx < m.hdrcount; ++idx) {
04918 ast_free((void *) m.headers[idx]);
04919 }
04920 return res;
04921 }
04922
04923
04924
04925
04926
04927
04928
04929
04930
04931 static void *session_do(void *data)
04932 {
04933 struct ast_tcptls_session_instance *ser = data;
04934 struct mansession_session *session;
04935 struct mansession s = {
04936 .tcptls_session = data,
04937 };
04938 int flags;
04939 int res;
04940 struct sockaddr_in ser_remote_address_tmp;
04941 struct protoent *p;
04942
04943 if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
04944 fclose(ser->f);
04945 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04946 goto done;
04947 }
04948
04949 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
04950 session = build_mansession(ser_remote_address_tmp);
04951
04952 if (session == NULL) {
04953 fclose(ser->f);
04954 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04955 goto done;
04956 }
04957
04958
04959
04960
04961 p = getprotobyname("tcp");
04962 if (p) {
04963 int arg = 1;
04964 if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
04965 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));
04966 }
04967 } else {
04968 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");
04969 }
04970
04971 flags = fcntl(ser->fd, F_GETFL);
04972 if (!block_sockets) {
04973 flags |= O_NONBLOCK;
04974 } else {
04975 flags &= ~O_NONBLOCK;
04976 }
04977 fcntl(ser->fd, F_SETFL, flags);
04978
04979 ao2_lock(session);
04980
04981 session->last_ev = grab_last();
04982
04983 ast_mutex_init(&s.lock);
04984
04985
04986 session->fd = s.fd = ser->fd;
04987 session->f = s.f = ser->f;
04988 session->sin = ser_remote_address_tmp;
04989 s.session = session;
04990
04991 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
04992
04993 if(time(&session->authstart) == -1) {
04994 ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
04995 ast_atomic_fetchadd_int(&unauth_sessions, -1);
04996 ao2_unlock(session);
04997 session_destroy(session);
04998 goto done;
04999 }
05000 ao2_unlock(session);
05001
05002 astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION);
05003 for (;;) {
05004 if ((res = do_message(&s)) < 0 || s.write_error) {
05005 break;
05006 }
05007 }
05008
05009 if (session->authenticated) {
05010 if (manager_displayconnects(session)) {
05011 ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05012 }
05013 } else {
05014 ast_atomic_fetchadd_int(&unauth_sessions, -1);
05015 if (displayconnects) {
05016 ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05017 }
05018 }
05019
05020 session_destroy(session);
05021
05022 ast_mutex_destroy(&s.lock);
05023 done:
05024 ao2_ref(ser, -1);
05025 ser = NULL;
05026 return NULL;
05027 }
05028
05029
05030 static void purge_sessions(int n_max)
05031 {
05032 struct mansession_session *session;
05033 time_t now = time(NULL);
05034 struct ao2_iterator i;
05035
05036 i = ao2_iterator_init(sessions, 0);
05037 while ((session = ao2_iterator_next(&i)) && n_max > 0) {
05038 ao2_lock(session);
05039 if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
05040 if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
05041 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
05042 session->username, ast_inet_ntoa(session->sin.sin_addr));
05043 }
05044 ao2_unlock(session);
05045 session_destroy(session);
05046 n_max--;
05047 } else {
05048 ao2_unlock(session);
05049 unref_mansession(session);
05050 }
05051 }
05052 ao2_iterator_destroy(&i);
05053 }
05054
05055
05056
05057
05058
05059 static int append_event(const char *str, int category)
05060 {
05061 struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
05062 static int seq;
05063
05064 if (!tmp) {
05065 return -1;
05066 }
05067
05068
05069 tmp->usecount = 0;
05070 tmp->category = category;
05071 tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
05072 tmp->tv = ast_tvnow();
05073 AST_RWLIST_NEXT(tmp, eq_next) = NULL;
05074 strcpy(tmp->eventdata, str);
05075
05076 AST_RWLIST_WRLOCK(&all_events);
05077 AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
05078 AST_RWLIST_UNLOCK(&all_events);
05079
05080 return 0;
05081 }
05082
05083 AST_THREADSTORAGE(manager_event_funcbuf);
05084
05085 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
05086 {
05087 struct manager_channel_variable *var;
05088
05089 AST_RWLIST_RDLOCK(&channelvars);
05090 AST_LIST_TRAVERSE(&channelvars, var, entry) {
05091 const char *val;
05092 struct ast_str *res;
05093
05094 if (var->isfunc) {
05095 res = ast_str_thread_get(&manager_event_funcbuf, 16);
05096 if (res && ast_func_read2(chan, var->name, &res, 0) == 0) {
05097 val = ast_str_buffer(res);
05098 } else {
05099 val = NULL;
05100 }
05101 } else {
05102 val = pbx_builtin_getvar_helper(chan, var->name);
05103 }
05104 ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", chan->name, var->name, val ? val : "");
05105 }
05106 AST_RWLIST_UNLOCK(&channelvars);
05107 }
05108
05109
05110 AST_THREADSTORAGE(manager_event_buf);
05111 #define MANAGER_EVENT_BUF_INITSIZE 256
05112
05113 int __ast_manager_event_multichan(int category, const char *event, int chancount, struct
05114 ast_channel **chans, const char *file, int line, const char *func, const char *fmt, ...)
05115 {
05116 struct mansession_session *session;
05117 struct manager_custom_hook *hook;
05118 struct ast_str *auth = ast_str_alloca(80);
05119 const char *cat_str;
05120 va_list ap;
05121 struct timeval now;
05122 struct ast_str *buf;
05123 int i;
05124
05125 if (!(sessions && ao2_container_count(sessions)) && AST_RWLIST_EMPTY(&manager_hooks)) {
05126 return 0;
05127 }
05128
05129 if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) {
05130 return -1;
05131 }
05132
05133 cat_str = authority_to_str(category, &auth);
05134 ast_str_set(&buf, 0,
05135 "Event: %s\r\nPrivilege: %s\r\n",
05136 event, cat_str);
05137
05138 if (timestampevents) {
05139 now = ast_tvnow();
05140 ast_str_append(&buf, 0,
05141 "Timestamp: %ld.%06lu\r\n",
05142 (long)now.tv_sec, (unsigned long) now.tv_usec);
05143 }
05144 if (manager_debug) {
05145 static int seq;
05146 ast_str_append(&buf, 0,
05147 "SequenceNumber: %d\r\n",
05148 ast_atomic_fetchadd_int(&seq, 1));
05149 ast_str_append(&buf, 0,
05150 "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
05151 }
05152
05153 va_start(ap, fmt);
05154 ast_str_append_va(&buf, 0, fmt, ap);
05155 va_end(ap);
05156 for (i = 0; i < chancount; i++) {
05157 append_channel_vars(&buf, chans[i]);
05158 }
05159
05160 ast_str_append(&buf, 0, "\r\n");
05161
05162 append_event(ast_str_buffer(buf), category);
05163
05164
05165 if (sessions) {
05166 struct ao2_iterator i;
05167 i = ao2_iterator_init(sessions, 0);
05168 while ((session = ao2_iterator_next(&i))) {
05169 ao2_lock(session);
05170 if (session->waiting_thread != AST_PTHREADT_NULL) {
05171 pthread_kill(session->waiting_thread, SIGURG);
05172 } else {
05173
05174
05175
05176
05177
05178 session->pending_event = 1;
05179 }
05180 ao2_unlock(session);
05181 unref_mansession(session);
05182 }
05183 ao2_iterator_destroy(&i);
05184 }
05185
05186 if (!AST_RWLIST_EMPTY(&manager_hooks)) {
05187 AST_RWLIST_RDLOCK(&manager_hooks);
05188 AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
05189 hook->helper(category, event, ast_str_buffer(buf));
05190 }
05191 AST_RWLIST_UNLOCK(&manager_hooks);
05192 }
05193
05194 return 0;
05195 }
05196
05197
05198
05199
05200 int ast_manager_unregister(char *action)
05201 {
05202 struct manager_action *cur;
05203
05204 AST_RWLIST_WRLOCK(&actions);
05205 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
05206 if (!strcasecmp(action, cur->action)) {
05207 AST_RWLIST_REMOVE_CURRENT(list);
05208 break;
05209 }
05210 }
05211 AST_RWLIST_TRAVERSE_SAFE_END;
05212 AST_RWLIST_UNLOCK(&actions);
05213
05214 if (cur) {
05215 time_t now;
05216
05217
05218
05219
05220
05221 ao2_lock(cur);
05222 cur->registered = 0;
05223 ao2_unlock(cur);
05224
05225
05226
05227
05228
05229
05230 now = time(NULL);
05231 while (cur->active_count) {
05232 if (5 <= time(NULL) - now) {
05233 ast_debug(1,
05234 "Unregister manager action %s timed out waiting for %d active instances to complete\n",
05235 action, cur->active_count);
05236 break;
05237 }
05238
05239 sched_yield();
05240 }
05241
05242 ao2_t_ref(cur, -1, "action object removed from list");
05243 ast_verb(2, "Manager unregistered action %s\n", action);
05244 }
05245
05246 return 0;
05247 }
05248
05249 static int manager_state_cb(char *context, char *exten, int state, void *data)
05250 {
05251
05252 char hint[512];
05253 ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
05254
05255 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
05256 return 0;
05257 }
05258
05259 static int ast_manager_register_struct(struct manager_action *act)
05260 {
05261 struct manager_action *cur, *prev = NULL;
05262
05263 AST_RWLIST_WRLOCK(&actions);
05264 AST_RWLIST_TRAVERSE(&actions, cur, list) {
05265 int ret;
05266
05267 ret = strcasecmp(cur->action, act->action);
05268 if (ret == 0) {
05269 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
05270 AST_RWLIST_UNLOCK(&actions);
05271 return -1;
05272 }
05273 if (ret > 0) {
05274 prev = cur;
05275 break;
05276 }
05277 }
05278
05279 ao2_t_ref(act, +1, "action object added to list");
05280 act->registered = 1;
05281 if (prev) {
05282 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
05283 } else {
05284 AST_RWLIST_INSERT_HEAD(&actions, act, list);
05285 }
05286
05287 ast_verb(2, "Manager registered action %s\n", act->action);
05288
05289 AST_RWLIST_UNLOCK(&actions);
05290
05291 return 0;
05292 }
05293
05294
05295
05296
05297
05298
05299
05300
05301
05302 static void action_destroy(void *obj)
05303 {
05304 struct manager_action *doomed = obj;
05305
05306 if (doomed->synopsis) {
05307
05308 ast_string_field_free_memory(doomed);
05309 }
05310 }
05311
05312
05313
05314 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
05315 {
05316 struct manager_action *cur;
05317
05318 cur = ao2_alloc(sizeof(*cur), action_destroy);
05319 if (!cur) {
05320 return -1;
05321 }
05322 if (ast_string_field_init(cur, 128)) {
05323 ao2_t_ref(cur, -1, "action object creation failed");
05324 return -1;
05325 }
05326
05327 cur->action = action;
05328 cur->authority = auth;
05329 cur->func = func;
05330 #ifdef AST_XML_DOCS
05331 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
05332 char *tmpxml;
05333
05334 tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
05335 ast_string_field_set(cur, synopsis, tmpxml);
05336 ast_free(tmpxml);
05337
05338 tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
05339 ast_string_field_set(cur, syntax, tmpxml);
05340 ast_free(tmpxml);
05341
05342 tmpxml = ast_xmldoc_build_description("manager", action, NULL);
05343 ast_string_field_set(cur, description, tmpxml);
05344 ast_free(tmpxml);
05345
05346 tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
05347 ast_string_field_set(cur, seealso, tmpxml);
05348 ast_free(tmpxml);
05349
05350 tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
05351 ast_string_field_set(cur, arguments, tmpxml);
05352 ast_free(tmpxml);
05353
05354 cur->docsrc = AST_XML_DOC;
05355 } else
05356 #endif
05357 {
05358 ast_string_field_set(cur, synopsis, synopsis);
05359 ast_string_field_set(cur, description, description);
05360 #ifdef AST_XML_DOCS
05361 cur->docsrc = AST_STATIC_DOC;
05362 #endif
05363 }
05364 if (ast_manager_register_struct(cur)) {
05365 ao2_t_ref(cur, -1, "action object registration failed");
05366 return -1;
05367 }
05368
05369 ao2_t_ref(cur, -1, "action object registration successful");
05370 return 0;
05371 }
05372
05373
05374
05375
05376
05377
05378
05379
05380
05381
05382
05383
05384
05385
05386
05387 enum output_format {
05388 FORMAT_RAW,
05389 FORMAT_HTML,
05390 FORMAT_XML,
05391 };
05392
05393 static const char * const contenttype[] = {
05394 [FORMAT_RAW] = "plain",
05395 [FORMAT_HTML] = "html",
05396 [FORMAT_XML] = "xml",
05397 };
05398
05399
05400
05401
05402
05403
05404 static struct mansession_session *find_session(uint32_t ident, int incinuse)
05405 {
05406 struct mansession_session *session;
05407 struct ao2_iterator i;
05408
05409 if (ident == 0) {
05410 return NULL;
05411 }
05412
05413 i = ao2_iterator_init(sessions, 0);
05414 while ((session = ao2_iterator_next(&i))) {
05415 ao2_lock(session);
05416 if (session->managerid == ident && !session->needdestroy) {
05417 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05418 break;
05419 }
05420 ao2_unlock(session);
05421 unref_mansession(session);
05422 }
05423 ao2_iterator_destroy(&i);
05424
05425 return session;
05426 }
05427
05428
05429
05430
05431
05432
05433
05434
05435
05436
05437 static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
05438 {
05439 struct mansession_session *session;
05440 struct ao2_iterator i;
05441
05442 if (nonce == 0 || username == NULL || stale == NULL) {
05443 return NULL;
05444 }
05445
05446 i = ao2_iterator_init(sessions, 0);
05447 while ((session = ao2_iterator_next(&i))) {
05448 ao2_lock(session);
05449 if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05450 *stale = 0;
05451 break;
05452 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05453 *stale = 1;
05454 break;
05455 }
05456 ao2_unlock(session);
05457 unref_mansession(session);
05458 }
05459 ao2_iterator_destroy(&i);
05460 return session;
05461 }
05462
05463 int astman_is_authed(uint32_t ident)
05464 {
05465 int authed;
05466 struct mansession_session *session;
05467
05468 if (!(session = find_session(ident, 0)))
05469 return 0;
05470
05471 authed = (session->authenticated != 0);
05472
05473 ao2_unlock(session);
05474 unref_mansession(session);
05475
05476 return authed;
05477 }
05478
05479 int astman_verify_session_readpermissions(uint32_t ident, int perm)
05480 {
05481 int result = 0;
05482 struct mansession_session *session;
05483 struct ao2_iterator i;
05484
05485 if (ident == 0) {
05486 return 0;
05487 }
05488
05489 i = ao2_iterator_init(sessions, 0);
05490 while ((session = ao2_iterator_next(&i))) {
05491 ao2_lock(session);
05492 if ((session->managerid == ident) && (session->readperm & perm)) {
05493 result = 1;
05494 ao2_unlock(session);
05495 unref_mansession(session);
05496 break;
05497 }
05498 ao2_unlock(session);
05499 unref_mansession(session);
05500 }
05501 ao2_iterator_destroy(&i);
05502 return result;
05503 }
05504
05505 int astman_verify_session_writepermissions(uint32_t ident, int perm)
05506 {
05507 int result = 0;
05508 struct mansession_session *session;
05509 struct ao2_iterator i;
05510
05511 if (ident == 0) {
05512 return 0;
05513 }
05514
05515 i = ao2_iterator_init(sessions, 0);
05516 while ((session = ao2_iterator_next(&i))) {
05517 ao2_lock(session);
05518 if ((session->managerid == ident) && (session->writeperm & perm)) {
05519 result = 1;
05520 ao2_unlock(session);
05521 unref_mansession(session);
05522 break;
05523 }
05524 ao2_unlock(session);
05525 unref_mansession(session);
05526 }
05527 ao2_iterator_destroy(&i);
05528 return result;
05529 }
05530
05531
05532
05533
05534
05535
05536 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
05537 {
05538
05539 char buf[256];
05540 char *dst = buf;
05541 int space = sizeof(buf);
05542
05543 for ( ; *src || dst != buf ; src++) {
05544 if (*src == '\0' || space < 10) {
05545 *dst++ = '\0';
05546 ast_str_append(out, 0, "%s", buf);
05547 dst = buf;
05548 space = sizeof(buf);
05549 if (*src == '\0') {
05550 break;
05551 }
05552 }
05553
05554 if ( (mode & 2) && !isalnum(*src)) {
05555 *dst++ = '_';
05556 space--;
05557 continue;
05558 }
05559 switch (*src) {
05560 case '<':
05561 strcpy(dst, "<");
05562 dst += 4;
05563 space -= 4;
05564 break;
05565 case '>':
05566 strcpy(dst, ">");
05567 dst += 4;
05568 space -= 4;
05569 break;
05570 case '\"':
05571 strcpy(dst, """);
05572 dst += 6;
05573 space -= 6;
05574 break;
05575 case '\'':
05576 strcpy(dst, "'");
05577 dst += 6;
05578 space -= 6;
05579 break;
05580 case '&':
05581 strcpy(dst, "&");
05582 dst += 5;
05583 space -= 5;
05584 break;
05585
05586 default:
05587 *dst++ = mode ? tolower(*src) : *src;
05588 space--;
05589 }
05590 }
05591 }
05592
05593 struct variable_count {
05594 char *varname;
05595 int count;
05596 };
05597
05598 static int variable_count_hash_fn(const void *vvc, const int flags)
05599 {
05600 const struct variable_count *vc = vvc;
05601
05602 return ast_str_hash(vc->varname);
05603 }
05604
05605 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
05606 {
05607
05608
05609
05610
05611 struct variable_count *vc = obj;
05612 char *str = vstr;
05613 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05614 }
05615
05616
05617
05618
05619
05620
05621
05622
05623
05624
05625
05626
05627
05628
05629
05630
05631
05632
05633
05634
05635
05636
05637
05638
05639
05640
05641
05642
05643
05644 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
05645 {
05646 struct ast_variable *v;
05647 const char *dest = NULL;
05648 char *var, *val;
05649 const char *objtype = NULL;
05650 int in_data = 0;
05651 int inobj = 0;
05652 int xml = (format == FORMAT_XML);
05653 struct variable_count *vc = NULL;
05654 struct ao2_container *vco = NULL;
05655
05656 if (xml) {
05657
05658 for (v = get_vars; v; v = v->next) {
05659 if (!strcasecmp(v->name, "ajaxdest")) {
05660 dest = v->value;
05661 } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05662 objtype = v->value;
05663 }
05664 }
05665 if (ast_strlen_zero(dest)) {
05666 dest = "unknown";
05667 }
05668 if (ast_strlen_zero(objtype)) {
05669 objtype = "generic";
05670 }
05671 }
05672
05673
05674 while (in && *in) {
05675 val = strsep(&in, "\r\n");
05676 if (in && *in == '\n') {
05677 in++;
05678 }
05679 ast_trim_blanks(val);
05680 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05681 if (ast_strlen_zero(val)) {
05682
05683 if (in_data) {
05684
05685 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05686 in_data = 0;
05687 }
05688
05689 if (inobj) {
05690
05691 ast_str_append(out, 0, xml ? " /></response>\n" :
05692 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05693 inobj = 0;
05694 ao2_ref(vco, -1);
05695 vco = NULL;
05696 }
05697 continue;
05698 }
05699
05700 if (!inobj) {
05701
05702 if (xml) {
05703 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05704 }
05705 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05706 inobj = 1;
05707 }
05708
05709 if (in_data) {
05710
05711
05712 ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05713 xml_copy_escape(out, val, 0);
05714 continue;
05715 }
05716
05717
05718 var = strsep(&val, ":");
05719 if (val) {
05720
05721 val = ast_skip_blanks(val);
05722 ast_trim_blanks(var);
05723 } else {
05724
05725 val = var;
05726 var = "Opaque-data";
05727 in_data = 1;
05728 }
05729
05730
05731 ast_str_append(out, 0, xml ? " " : "<tr><td>");
05732 if ((vc = ao2_find(vco, var, 0))) {
05733 vc->count++;
05734 } else {
05735
05736 vc = ao2_alloc(sizeof(*vc), NULL);
05737 vc->varname = var;
05738 vc->count = 1;
05739 ao2_link(vco, vc);
05740 }
05741
05742 xml_copy_escape(out, var, xml ? 1 | 2 : 0);
05743 if (vc->count > 1) {
05744 ast_str_append(out, 0, "-%d", vc->count);
05745 }
05746 ao2_ref(vc, -1);
05747 ast_str_append(out, 0, xml ? "='" : "</td><td>");
05748 xml_copy_escape(out, val, 0);
05749 if (!in_data || !*in) {
05750 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05751 }
05752 }
05753
05754 if (inobj) {
05755 ast_str_append(out, 0, xml ? " /></response>\n" :
05756 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05757 ao2_ref(vco, -1);
05758 }
05759 }
05760
05761 static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
05762 {
05763 char *buf;
05764 size_t l;
05765
05766 if (!s->f)
05767 return;
05768
05769
05770 fprintf(s->f, "%c", 0);
05771 fflush(s->f);
05772
05773 if ((l = ftell(s->f)) > 0) {
05774 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
05775 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
05776 } else {
05777 if (format == FORMAT_XML || format == FORMAT_HTML) {
05778 xml_translate(out, buf, params, format);
05779 } else {
05780 ast_str_append(out, 0, "%s", buf);
05781 }
05782 munmap(buf, l);
05783 }
05784 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05785 xml_translate(out, "", params, format);
05786 }
05787
05788 if (s->f) {
05789 if (fclose(s->f)) {
05790 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
05791 }
05792 s->f = NULL;
05793 s->fd = -1;
05794 } else if (s->fd != -1) {
05795 if (close(s->fd)) {
05796 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
05797 }
05798 s->fd = -1;
05799 } else {
05800 ast_log(LOG_ERROR, "process output attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
05801 }
05802 }
05803
05804 static int generic_http_callback(struct ast_tcptls_session_instance *ser,
05805 enum ast_http_method method,
05806 enum output_format format,
05807 struct sockaddr_in *remote_address, const char *uri,
05808 struct ast_variable *get_params,
05809 struct ast_variable *headers)
05810 {
05811 struct mansession s = { .session = NULL, .tcptls_session = ser };
05812 struct mansession_session *session = NULL;
05813 uint32_t ident = 0;
05814 int blastaway = 0;
05815 struct ast_variable *v, *cookies, *params = get_params;
05816 char template[] = "/tmp/ast-http-XXXXXX";
05817 struct ast_str *http_header = NULL, *out = NULL;
05818 struct message m = { 0 };
05819 unsigned int idx;
05820 size_t hdrlen;
05821
05822 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05823 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05824 return -1;
05825 }
05826
05827 cookies = ast_http_get_cookies(headers);
05828 for (v = cookies; v; v = v->next) {
05829 if (!strcasecmp(v->name, "mansession_id")) {
05830 sscanf(v->value, "%30x", &ident);
05831 break;
05832 }
05833 }
05834 if (cookies) {
05835 ast_variables_destroy(cookies);
05836 }
05837
05838 if (!(session = find_session(ident, 1))) {
05839
05840
05841
05842
05843
05844 if (!(session = build_mansession(*remote_address))) {
05845 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05846 return -1;
05847 }
05848 ao2_lock(session);
05849 session->sin = *remote_address;
05850 session->fd = -1;
05851 session->waiting_thread = AST_PTHREADT_NULL;
05852 session->send_events = 0;
05853 session->inuse = 1;
05854
05855
05856
05857
05858
05859 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
05860 session->last_ev = grab_last();
05861 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05862 }
05863 ao2_unlock(session);
05864
05865 http_header = ast_str_create(128);
05866 out = ast_str_create(2048);
05867
05868 ast_mutex_init(&s.lock);
05869
05870 if (http_header == NULL || out == NULL) {
05871 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05872 goto generic_callback_out;
05873 }
05874
05875 s.session = session;
05876 s.fd = mkstemp(template);
05877 unlink(template);
05878 if (s.fd <= -1) {
05879 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05880 goto generic_callback_out;
05881 }
05882 s.f = fdopen(s.fd, "w+");
05883 if (!s.f) {
05884 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05885 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05886 close(s.fd);
05887 goto generic_callback_out;
05888 }
05889
05890 if (method == AST_HTTP_POST) {
05891 params = ast_http_get_post_vars(ser, headers);
05892 }
05893
05894 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
05895 hdrlen = strlen(v->name) + strlen(v->value) + 3;
05896 m.headers[m.hdrcount] = ast_malloc(hdrlen);
05897 if (!m.headers[m.hdrcount]) {
05898
05899 continue;
05900 }
05901 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05902 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05903 ++m.hdrcount;
05904 }
05905
05906 if (process_message(&s, &m)) {
05907 if (session->authenticated) {
05908 if (manager_displayconnects(session)) {
05909 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05910 }
05911 } else {
05912 if (displayconnects) {
05913 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05914 }
05915 }
05916 session->needdestroy = 1;
05917 }
05918
05919
05920 for (idx = 0; idx < m.hdrcount; ++idx) {
05921 ast_free((void *) m.headers[idx]);
05922 m.headers[idx] = NULL;
05923 }
05924
05925 ast_str_append(&http_header, 0,
05926 "Content-type: text/%s\r\n"
05927 "Cache-Control: no-cache;\r\n"
05928 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
05929 "Pragma: SuppressEvents\r\n",
05930 contenttype[format],
05931 session->managerid, httptimeout);
05932
05933 if (format == FORMAT_XML) {
05934 ast_str_append(&out, 0, "<ajax-response>\n");
05935 } else if (format == FORMAT_HTML) {
05936
05937
05938
05939
05940
05941
05942 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
05943 #define TEST_STRING \
05944 "<form action=\"manager\" method=\"post\">\n\
05945 Action: <select name=\"action\">\n\
05946 <option value=\"\">-----></option>\n\
05947 <option value=\"login\">login</option>\n\
05948 <option value=\"command\">Command</option>\n\
05949 <option value=\"waitevent\">waitevent</option>\n\
05950 <option value=\"listcommands\">listcommands</option>\n\
05951 </select>\n\
05952 or <input name=\"action\"><br/>\n\
05953 CLI Command <input name=\"command\"><br>\n\
05954 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
05955 <input type=\"submit\">\n</form>\n"
05956
05957 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>");
05958 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
05959 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
05960 ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
05961 }
05962
05963 process_output(&s, &out, params, format);
05964
05965 if (format == FORMAT_XML) {
05966 ast_str_append(&out, 0, "</ajax-response>\n");
05967 } else if (format == FORMAT_HTML) {
05968 ast_str_append(&out, 0, "</table></body>\r\n");
05969 }
05970
05971 ao2_lock(session);
05972
05973 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
05974
05975 if (session->needdestroy) {
05976 if (session->inuse == 1) {
05977 ast_debug(1, "Need destroy, doing it now!\n");
05978 blastaway = 1;
05979 } else {
05980 ast_debug(1, "Need destroy, but can't do it yet!\n");
05981 if (session->waiting_thread != AST_PTHREADT_NULL) {
05982 pthread_kill(session->waiting_thread, SIGURG);
05983 }
05984 session->inuse--;
05985 }
05986 } else {
05987 session->inuse--;
05988 }
05989 ao2_unlock(session);
05990
05991 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05992 http_header = out = NULL;
05993
05994 generic_callback_out:
05995 ast_mutex_destroy(&s.lock);
05996
05997
05998
05999 if (method == AST_HTTP_POST && params) {
06000 ast_variables_destroy(params);
06001 }
06002 if (http_header) {
06003 ast_free(http_header);
06004 }
06005 if (out) {
06006 ast_free(out);
06007 }
06008
06009 if (session && blastaway) {
06010 session_destroy(session);
06011 } else if (session && session->f) {
06012 fclose(session->f);
06013 session->f = NULL;
06014 }
06015
06016 return 0;
06017 }
06018
06019 static int auth_http_callback(struct ast_tcptls_session_instance *ser,
06020 enum ast_http_method method,
06021 enum output_format format,
06022 struct sockaddr_in *remote_address, const char *uri,
06023 struct ast_variable *get_params,
06024 struct ast_variable *headers)
06025 {
06026 struct mansession_session *session = NULL;
06027 struct mansession s = { .session = NULL, .tcptls_session = ser };
06028 struct ast_variable *v, *params = get_params;
06029 char template[] = "/tmp/ast-http-XXXXXX";
06030 struct ast_str *http_header = NULL, *out = NULL;
06031 size_t result_size = 512;
06032 struct message m = { 0 };
06033 unsigned int idx;
06034 size_t hdrlen;
06035
06036 time_t time_now = time(NULL);
06037 unsigned long nonce = 0, nc;
06038 struct ast_http_digest d = { NULL, };
06039 struct ast_manager_user *user = NULL;
06040 int stale = 0;
06041 char resp_hash[256]="";
06042
06043 char u_username[80];
06044 int u_readperm;
06045 int u_writeperm;
06046 int u_writetimeout;
06047 int u_displayconnects;
06048 struct ast_sockaddr addr;
06049
06050 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
06051 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
06052 return -1;
06053 }
06054
06055
06056 for (v = headers; v; v = v->next) {
06057 if (!strcasecmp(v->name, "Authorization")) {
06058 break;
06059 }
06060 }
06061
06062 if (!v || ast_strlen_zero(v->value)) {
06063 goto out_401;
06064 }
06065
06066
06067 if (ast_string_field_init(&d, 128)) {
06068 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06069 return -1;
06070 }
06071
06072 if (ast_parse_digest(v->value, &d, 0, 1)) {
06073
06074 nonce = 0;
06075 goto out_401;
06076 }
06077 if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
06078 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
06079 nonce = 0;
06080 goto out_401;
06081 }
06082
06083 AST_RWLIST_WRLOCK(&users);
06084 user = get_manager_by_name_locked(d.username);
06085 if(!user) {
06086 AST_RWLIST_UNLOCK(&users);
06087 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06088 nonce = 0;
06089 goto out_401;
06090 }
06091
06092 ast_sockaddr_from_sin(&addr, remote_address);
06093
06094 if (user->ha && !ast_apply_ha(user->ha, &addr)) {
06095 AST_RWLIST_UNLOCK(&users);
06096 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06097 ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
06098 return -1;
06099 }
06100
06101
06102
06103
06104 {
06105 char a2[256];
06106 char a2_hash[256];
06107 char resp[256];
06108
06109
06110 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
06111 ast_md5_hash(a2_hash, a2);
06112
06113 if (d.qop) {
06114
06115 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
06116 } else {
06117
06118 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
06119 }
06120 ast_md5_hash(resp_hash, resp);
06121 }
06122
06123 if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
06124
06125 AST_RWLIST_UNLOCK(&users);
06126 nonce = 0;
06127 goto out_401;
06128 }
06129
06130
06131
06132
06133
06134 ast_copy_string(u_username, user->username, sizeof(u_username));
06135 u_readperm = user->readperm;
06136 u_writeperm = user->writeperm;
06137 u_displayconnects = user->displayconnects;
06138 u_writetimeout = user->writetimeout;
06139 AST_RWLIST_UNLOCK(&users);
06140
06141 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
06142
06143
06144
06145
06146 if (!(session = build_mansession(*remote_address))) {
06147 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06148 return -1;
06149 }
06150 ao2_lock(session);
06151
06152 ast_copy_string(session->username, u_username, sizeof(session->username));
06153 session->managerid = nonce;
06154 session->last_ev = grab_last();
06155 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06156
06157 session->readperm = u_readperm;
06158 session->writeperm = u_writeperm;
06159 session->writetimeout = u_writetimeout;
06160
06161 if (u_displayconnects) {
06162 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06163 }
06164 session->noncetime = session->sessionstart = time_now;
06165 session->authenticated = 1;
06166 } else if (stale) {
06167
06168
06169
06170
06171
06172
06173
06174
06175
06176
06177
06178
06179 nonce = session->managerid;
06180 ao2_unlock(session);
06181 stale = 1;
06182 goto out_401;
06183 } else {
06184 sscanf(d.nc, "%30lx", &nc);
06185 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
06186
06187
06188
06189
06190
06191
06192
06193 session->nc = 0;
06194 session->oldnonce = session->managerid;
06195 nonce = session->managerid = ast_random();
06196 session->noncetime = time_now;
06197 ao2_unlock(session);
06198 stale = 1;
06199 goto out_401;
06200 } else {
06201 session->nc = nc;
06202 }
06203 }
06204
06205
06206
06207 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
06208 ao2_unlock(session);
06209
06210 ast_mutex_init(&s.lock);
06211 s.session = session;
06212 s.fd = mkstemp(template);
06213 unlink(template);
06214 if (s.fd <= -1) {
06215 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06216 goto auth_callback_out;
06217 }
06218 s.f = fdopen(s.fd, "w+");
06219 if (!s.f) {
06220 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06221 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06222 close(s.fd);
06223 goto auth_callback_out;
06224 }
06225
06226 if (method == AST_HTTP_POST) {
06227 params = ast_http_get_post_vars(ser, headers);
06228 }
06229
06230 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06231 hdrlen = strlen(v->name) + strlen(v->value) + 3;
06232 m.headers[m.hdrcount] = ast_malloc(hdrlen);
06233 if (!m.headers[m.hdrcount]) {
06234
06235 continue;
06236 }
06237 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06238 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06239 ++m.hdrcount;
06240 }
06241
06242 if (process_message(&s, &m)) {
06243 if (u_displayconnects) {
06244 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06245 }
06246
06247 session->needdestroy = 1;
06248 }
06249
06250
06251 for (idx = 0; idx < m.hdrcount; ++idx) {
06252 ast_free((void *) m.headers[idx]);
06253 m.headers[idx] = NULL;
06254 }
06255
06256 if (s.f) {
06257 result_size = ftell(s.f);
06258 }
06259
06260 http_header = ast_str_create(80);
06261 out = ast_str_create(result_size * 2 + 512);
06262
06263 if (http_header == NULL || out == NULL) {
06264 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06265 goto auth_callback_out;
06266 }
06267
06268 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
06269
06270 if (format == FORMAT_XML) {
06271 ast_str_append(&out, 0, "<ajax-response>\n");
06272 } else if (format == FORMAT_HTML) {
06273 ast_str_append(&out, 0,
06274 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
06275 "<html><head>\r\n"
06276 "<title>Asterisk™ Manager Interface</title>\r\n"
06277 "</head><body style=\"background-color: #ffffff;\">\r\n"
06278 "<form method=\"POST\">\r\n"
06279 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
06280 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
06281 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
06282 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
06283 }
06284
06285 process_output(&s, &out, params, format);
06286
06287 if (format == FORMAT_XML) {
06288 ast_str_append(&out, 0, "</ajax-response>\n");
06289 } else if (format == FORMAT_HTML) {
06290 ast_str_append(&out, 0, "</table></form></body></html>\r\n");
06291 }
06292
06293 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06294 http_header = out = NULL;
06295
06296 auth_callback_out:
06297 ast_mutex_destroy(&s.lock);
06298
06299
06300 if (method == AST_HTTP_POST && params) {
06301 ast_variables_destroy(params);
06302 }
06303
06304 ast_free(http_header);
06305 ast_free(out);
06306
06307 ao2_lock(session);
06308 if (session->f) {
06309 fclose(session->f);
06310 }
06311 session->f = NULL;
06312 session->fd = -1;
06313 ao2_unlock(session);
06314
06315 if (session->needdestroy) {
06316 ast_debug(1, "Need destroy, doing it now!\n");
06317 session_destroy(session);
06318 }
06319 ast_string_field_free_memory(&d);
06320 return 0;
06321
06322 out_401:
06323 if (!nonce) {
06324 nonce = ast_random();
06325 }
06326
06327 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
06328 ast_string_field_free_memory(&d);
06329 return 0;
06330 }
06331
06332 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)
06333 {
06334 int retval;
06335 struct sockaddr_in ser_remote_address_tmp;
06336
06337 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06338 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06339 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06340 return retval;
06341 }
06342
06343 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)
06344 {
06345 int retval;
06346 struct sockaddr_in ser_remote_address_tmp;
06347
06348 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06349 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06350 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06351 return retval;
06352 }
06353
06354 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)
06355 {
06356 int retval;
06357 struct sockaddr_in ser_remote_address_tmp;
06358
06359 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06360 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06361 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06362 return retval;
06363 }
06364
06365 static struct ast_http_uri rawmanuri = {
06366 .description = "Raw HTTP Manager Event Interface",
06367 .uri = "rawman",
06368 .callback = rawman_http_callback,
06369 .data = NULL,
06370 .key = __FILE__,
06371 };
06372
06373 static struct ast_http_uri manageruri = {
06374 .description = "HTML Manager Event Interface",
06375 .uri = "manager",
06376 .callback = manager_http_callback,
06377 .data = NULL,
06378 .key = __FILE__,
06379 };
06380
06381 static struct ast_http_uri managerxmluri = {
06382 .description = "XML Manager Event Interface",
06383 .uri = "mxml",
06384 .callback = mxml_http_callback,
06385 .data = NULL,
06386 .key = __FILE__,
06387 };
06388
06389
06390
06391 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)
06392 {
06393 int retval;
06394 struct sockaddr_in ser_remote_address_tmp;
06395
06396 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06397 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06398 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06399 return retval;
06400 }
06401
06402 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)
06403 {
06404 int retval;
06405 struct sockaddr_in ser_remote_address_tmp;
06406
06407 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06408 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06409 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06410 return retval;
06411 }
06412
06413 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)
06414 {
06415 int retval;
06416 struct sockaddr_in ser_remote_address_tmp;
06417
06418 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06419 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06420 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06421 return retval;
06422 }
06423
06424 static struct ast_http_uri arawmanuri = {
06425 .description = "Raw HTTP Manager Event Interface w/Digest authentication",
06426 .uri = "arawman",
06427 .has_subtree = 0,
06428 .callback = auth_rawman_http_callback,
06429 .data = NULL,
06430 .key = __FILE__,
06431 };
06432
06433 static struct ast_http_uri amanageruri = {
06434 .description = "HTML Manager Event Interface w/Digest authentication",
06435 .uri = "amanager",
06436 .has_subtree = 0,
06437 .callback = auth_manager_http_callback,
06438 .data = NULL,
06439 .key = __FILE__,
06440 };
06441
06442 static struct ast_http_uri amanagerxmluri = {
06443 .description = "XML Manager Event Interface w/Digest authentication",
06444 .uri = "amxml",
06445 .has_subtree = 0,
06446 .callback = auth_mxml_http_callback,
06447 .data = NULL,
06448 .key = __FILE__,
06449 };
06450
06451 static int registered = 0;
06452 static int webregged = 0;
06453
06454
06455
06456
06457 static void purge_old_stuff(void *data)
06458 {
06459 purge_sessions(1);
06460 purge_events();
06461 }
06462
06463 static struct ast_tls_config ami_tls_cfg;
06464 static struct ast_tcptls_session_args ami_desc = {
06465 .accept_fd = -1,
06466 .master = AST_PTHREADT_NULL,
06467 .tls_cfg = NULL,
06468 .poll_timeout = 5000,
06469 .periodic_fn = purge_old_stuff,
06470 .name = "AMI server",
06471 .accept_fn = ast_tcptls_server_root,
06472 .worker_fn = session_do,
06473 };
06474
06475 static struct ast_tcptls_session_args amis_desc = {
06476 .accept_fd = -1,
06477 .master = AST_PTHREADT_NULL,
06478 .tls_cfg = &ami_tls_cfg,
06479 .poll_timeout = -1,
06480 .name = "AMI TLS server",
06481 .accept_fn = ast_tcptls_server_root,
06482 .worker_fn = session_do,
06483 };
06484
06485
06486 static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06487 {
06488 switch (cmd) {
06489 case CLI_INIT:
06490 e->command = "manager show settings";
06491 e->usage =
06492 "Usage: manager show settings\n"
06493 " Provides detailed list of the configuration of the Manager.\n";
06494 return NULL;
06495 case CLI_GENERATE:
06496 return NULL;
06497 }
06498 #define FORMAT " %-25.25s %-15.15s\n"
06499 #define FORMAT2 " %-25.25s %-15d\n"
06500 if (a->argc != 3) {
06501 return CLI_SHOWUSAGE;
06502 }
06503 ast_cli(a->fd, "\nGlobal Settings:\n");
06504 ast_cli(a->fd, "----------------\n");
06505 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06506 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06507 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06508 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06509 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06510 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06511 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06512 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06513 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06514 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06515 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06516 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06517 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06518 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06519 ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06520 #undef FORMAT
06521 #undef FORMAT2
06522
06523 return CLI_SUCCESS;
06524 }
06525
06526 static struct ast_cli_entry cli_manager[] = {
06527 AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
06528 AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
06529 AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
06530 AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
06531 AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
06532 AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
06533 AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
06534 AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
06535 AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
06536 };
06537
06538
06539
06540
06541
06542
06543
06544
06545
06546 static void load_channelvars(struct ast_variable *var)
06547 {
06548 struct manager_channel_variable *mcv;
06549 char *remaining = ast_strdupa(var->value);
06550 char *next;
06551
06552 ast_free(manager_channelvars);
06553 manager_channelvars = ast_strdup(var->value);
06554
06555
06556
06557
06558
06559
06560 free_channelvars();
06561 AST_RWLIST_WRLOCK(&channelvars);
06562 while ((next = strsep(&remaining, ",|"))) {
06563 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06564 break;
06565 }
06566 strcpy(mcv->name, next);
06567 if (strchr(next, '(')) {
06568 mcv->isfunc = 1;
06569 }
06570 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06571 }
06572 AST_RWLIST_UNLOCK(&channelvars);
06573 }
06574
06575 static int __init_manager(int reload)
06576 {
06577 struct ast_config *ucfg = NULL, *cfg = NULL;
06578 const char *val;
06579 char *cat = NULL;
06580 int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06581 struct ast_manager_user *user = NULL;
06582 struct ast_variable *var;
06583 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06584 char a1[256];
06585 char a1_hash[256];
06586 struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06587 struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06588 int tls_was_enabled = 0;
06589
06590 if (!registered) {
06591
06592 ast_manager_register_xml("Ping", 0, action_ping);
06593 ast_manager_register_xml("Events", 0, action_events);
06594 ast_manager_register_xml("Logoff", 0, action_logoff);
06595 ast_manager_register_xml("Login", 0, action_login);
06596 ast_manager_register_xml("Challenge", 0, action_challenge);
06597 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06598 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06599 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06600 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06601 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06602 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06603 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06604 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06605 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06606 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06607 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06608 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06609 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06610 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06611 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06612 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06613 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06614 ast_manager_register_xml("ListCommands", 0, action_listcommands);
06615 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06616 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06617 ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06618 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06619 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06620 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06621 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06622 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06623 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06624 ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06625
06626 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06627 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06628 registered = 1;
06629
06630 append_event("Event: Placeholder\r\n\r\n", 0);
06631 }
06632 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
06633 return 0;
06634 }
06635
06636 manager_enabled = DEFAULT_ENABLED;
06637 webmanager_enabled = DEFAULT_WEBENABLED;
06638 manager_debug = DEFAULT_MANAGERDEBUG;
06639 displayconnects = DEFAULT_DISPLAYCONNECTS;
06640 broken_events_action = DEFAULT_BROKENEVENTSACTION;
06641 block_sockets = DEFAULT_BLOCKSOCKETS;
06642 timestampevents = DEFAULT_TIMESTAMPEVENTS;
06643 httptimeout = DEFAULT_HTTPTIMEOUT;
06644 authtimeout = DEFAULT_AUTHTIMEOUT;
06645 authlimit = DEFAULT_AUTHLIMIT;
06646
06647 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06648 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
06649 return 0;
06650 }
06651
06652
06653 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
06654 ast_sockaddr_setnull(&ami_desc.local_address);
06655 ast_sockaddr_setnull(&amis_desc.local_address);
06656
06657 ami_desc_local_address_tmp.sin_family = AF_INET;
06658 amis_desc_local_address_tmp.sin_family = AF_INET;
06659
06660 ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06661
06662 tls_was_enabled = (reload && ami_tls_cfg.enabled);
06663
06664 ami_tls_cfg.enabled = 0;
06665 if (ami_tls_cfg.certfile) {
06666 ast_free(ami_tls_cfg.certfile);
06667 }
06668 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
06669 if (ami_tls_cfg.pvtfile) {
06670 ast_free(ami_tls_cfg.pvtfile);
06671 }
06672 ami_tls_cfg.pvtfile = ast_strdup("");
06673 if (ami_tls_cfg.cipher) {
06674 ast_free(ami_tls_cfg.cipher);
06675 }
06676 ami_tls_cfg.cipher = ast_strdup("");
06677
06678 free_channelvars();
06679
06680 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06681 val = var->value;
06682
06683 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06684 continue;
06685 }
06686
06687 if (!strcasecmp(var->name, "enabled")) {
06688 manager_enabled = ast_true(val);
06689 } else if (!strcasecmp(var->name, "block-sockets")) {
06690 block_sockets = ast_true(val);
06691 } else if (!strcasecmp(var->name, "webenabled")) {
06692 webmanager_enabled = ast_true(val);
06693 } else if (!strcasecmp(var->name, "port")) {
06694 ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06695 } else if (!strcasecmp(var->name, "bindaddr")) {
06696 if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06697 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06698 memset(&ami_desc_local_address_tmp.sin_addr, 0,
06699 sizeof(ami_desc_local_address_tmp.sin_addr));
06700 }
06701 } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06702 broken_events_action = ast_true(val);
06703 } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06704 allowmultiplelogin = ast_true(val);
06705 } else if (!strcasecmp(var->name, "displayconnects")) {
06706 displayconnects = ast_true(val);
06707 } else if (!strcasecmp(var->name, "timestampevents")) {
06708 timestampevents = ast_true(val);
06709 } else if (!strcasecmp(var->name, "debug")) {
06710 manager_debug = ast_true(val);
06711 } else if (!strcasecmp(var->name, "httptimeout")) {
06712 newhttptimeout = atoi(val);
06713 } else if (!strcasecmp(var->name, "authtimeout")) {
06714 int timeout = atoi(var->value);
06715
06716 if (timeout < 1) {
06717 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06718 } else {
06719 authtimeout = timeout;
06720 }
06721 } else if (!strcasecmp(var->name, "authlimit")) {
06722 int limit = atoi(var->value);
06723
06724 if (limit < 1) {
06725 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06726 } else {
06727 authlimit = limit;
06728 }
06729 } else if (!strcasecmp(var->name, "channelvars")) {
06730 load_channelvars(var);
06731 } else {
06732 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06733 var->name, val);
06734 }
06735 }
06736
06737 ast_sockaddr_to_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06738
06739
06740 if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06741 amis_desc_local_address_tmp.sin_addr =
06742 ami_desc_local_address_tmp.sin_addr;
06743 }
06744
06745 if (!amis_desc_local_address_tmp.sin_port) {
06746 amis_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_TLS_PORT);
06747 }
06748
06749 if (manager_enabled) {
06750 ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
06751 ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06752 }
06753
06754 AST_RWLIST_WRLOCK(&users);
06755
06756
06757 ucfg = ast_config_load2("users.conf", "manager", config_flags);
06758 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
06759 const char *hasmanager;
06760 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
06761
06762 while ((cat = ast_category_browse(ucfg, cat))) {
06763 if (!strcasecmp(cat, "general")) {
06764 continue;
06765 }
06766
06767 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
06768 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
06769 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
06770 const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
06771 const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
06772 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
06773 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
06774
06775
06776
06777
06778 if (!(user = get_manager_by_name_locked(cat))) {
06779 if (!(user = ast_calloc(1, sizeof(*user)))) {
06780 break;
06781 }
06782
06783
06784 ast_copy_string(user->username, cat, sizeof(user->username));
06785
06786 AST_LIST_INSERT_TAIL(&users, user, list);
06787 user->ha = NULL;
06788 user->keep = 1;
06789 user->readperm = -1;
06790 user->writeperm = -1;
06791
06792 user->displayconnects = displayconnects;
06793 user->writetimeout = 100;
06794 }
06795
06796 if (!user_secret) {
06797 user_secret = ast_variable_retrieve(ucfg, "general", "secret");
06798 }
06799 if (!user_read) {
06800 user_read = ast_variable_retrieve(ucfg, "general", "read");
06801 }
06802 if (!user_write) {
06803 user_write = ast_variable_retrieve(ucfg, "general", "write");
06804 }
06805 if (!user_displayconnects) {
06806 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
06807 }
06808 if (!user_writetimeout) {
06809 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
06810 }
06811
06812 if (!ast_strlen_zero(user_secret)) {
06813 if (user->secret) {
06814 ast_free(user->secret);
06815 }
06816 user->secret = ast_strdup(user_secret);
06817 }
06818
06819 if (user_read) {
06820 user->readperm = get_perm(user_read);
06821 }
06822 if (user_write) {
06823 user->writeperm = get_perm(user_write);
06824 }
06825 if (user_displayconnects) {
06826 user->displayconnects = ast_true(user_displayconnects);
06827 }
06828 if (user_writetimeout) {
06829 int value = atoi(user_writetimeout);
06830 if (value < 100) {
06831 ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
06832 } else {
06833 user->writetimeout = value;
06834 }
06835 }
06836 }
06837 }
06838 ast_config_destroy(ucfg);
06839 }
06840
06841
06842
06843 while ((cat = ast_category_browse(cfg, cat))) {
06844 struct ast_ha *oldha;
06845
06846 if (!strcasecmp(cat, "general")) {
06847 continue;
06848 }
06849
06850
06851 if (!(user = get_manager_by_name_locked(cat))) {
06852 if (!(user = ast_calloc(1, sizeof(*user)))) {
06853 break;
06854 }
06855
06856 ast_copy_string(user->username, cat, sizeof(user->username));
06857
06858 user->ha = NULL;
06859 user->readperm = 0;
06860 user->writeperm = 0;
06861
06862 user->displayconnects = displayconnects;
06863 user->writetimeout = 100;
06864 user->whitefilters = ao2_container_alloc(1, NULL, NULL);
06865 user->blackfilters = ao2_container_alloc(1, NULL, NULL);
06866
06867
06868 AST_RWLIST_INSERT_TAIL(&users, user, list);
06869 } else {
06870 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06871 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06872 }
06873
06874
06875 user->keep = 1;
06876 oldha = user->ha;
06877 user->ha = NULL;
06878
06879 var = ast_variable_browse(cfg, cat);
06880 for (; var; var = var->next) {
06881 if (!strcasecmp(var->name, "secret")) {
06882 if (user->secret) {
06883 ast_free(user->secret);
06884 }
06885 user->secret = ast_strdup(var->value);
06886 } else if (!strcasecmp(var->name, "deny") ||
06887 !strcasecmp(var->name, "permit")) {
06888 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
06889 } else if (!strcasecmp(var->name, "read") ) {
06890 user->readperm = get_perm(var->value);
06891 } else if (!strcasecmp(var->name, "write") ) {
06892 user->writeperm = get_perm(var->value);
06893 } else if (!strcasecmp(var->name, "displayconnects") ) {
06894 user->displayconnects = ast_true(var->value);
06895 } else if (!strcasecmp(var->name, "writetimeout")) {
06896 int value = atoi(var->value);
06897 if (value < 100) {
06898 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
06899 } else {
06900 user->writetimeout = value;
06901 }
06902 } else if (!strcasecmp(var->name, "eventfilter")) {
06903 const char *value = var->value;
06904 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
06905 if (new_filter) {
06906 int is_blackfilter;
06907 if (value[0] == '!') {
06908 is_blackfilter = 1;
06909 value++;
06910 } else {
06911 is_blackfilter = 0;
06912 }
06913 if (regcomp(new_filter, value, 0)) {
06914 ao2_t_ref(new_filter, -1, "failed to make regx");
06915 } else {
06916 if (is_blackfilter) {
06917 ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
06918 } else {
06919 ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
06920 }
06921 }
06922 }
06923 } else {
06924 ast_debug(1, "%s is an unknown option.\n", var->name);
06925 }
06926 }
06927 ast_free_ha(oldha);
06928 }
06929 ast_config_destroy(cfg);
06930
06931
06932 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
06933 if (user->keep) {
06934 user->keep = 0;
06935
06936
06937 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
06938 ast_md5_hash(a1_hash,a1);
06939 if (user->a1_hash) {
06940 ast_free(user->a1_hash);
06941 }
06942 user->a1_hash = ast_strdup(a1_hash);
06943 continue;
06944 }
06945
06946 AST_RWLIST_REMOVE_CURRENT(list);
06947 ast_debug(4, "Pruning user '%s'\n", user->username);
06948
06949 if (user->a1_hash) {
06950 ast_free(user->a1_hash);
06951 }
06952 if (user->secret) {
06953 ast_free(user->secret);
06954 }
06955 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06956 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06957 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06958 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06959 ast_free_ha(user->ha);
06960 ast_free(user);
06961 }
06962 AST_RWLIST_TRAVERSE_SAFE_END;
06963
06964 AST_RWLIST_UNLOCK(&users);
06965
06966 if (!reload) {
06967
06968 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06969 }
06970
06971 if (webmanager_enabled && manager_enabled) {
06972 if (!webregged) {
06973
06974 ast_http_uri_link(&rawmanuri);
06975 ast_http_uri_link(&manageruri);
06976 ast_http_uri_link(&managerxmluri);
06977
06978 ast_http_uri_link(&arawmanuri);
06979 ast_http_uri_link(&amanageruri);
06980 ast_http_uri_link(&amanagerxmluri);
06981 webregged = 1;
06982 }
06983 } else {
06984 if (webregged) {
06985 ast_http_uri_unlink(&rawmanuri);
06986 ast_http_uri_unlink(&manageruri);
06987 ast_http_uri_unlink(&managerxmluri);
06988
06989 ast_http_uri_unlink(&arawmanuri);
06990 ast_http_uri_unlink(&amanageruri);
06991 ast_http_uri_unlink(&amanagerxmluri);
06992 webregged = 0;
06993 }
06994 }
06995
06996 if (newhttptimeout > 0) {
06997 httptimeout = newhttptimeout;
06998 }
06999
07000 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
07001
07002 ast_tcptls_server_start(&ami_desc);
07003 if (tls_was_enabled && !ami_tls_cfg.enabled) {
07004 ast_tcptls_server_stop(&amis_desc);
07005 } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
07006 ast_tcptls_server_start(&amis_desc);
07007 }
07008 return 0;
07009 }
07010
07011
07012 static void free_channelvars(void)
07013 {
07014 struct manager_channel_variable *var;
07015 AST_RWLIST_WRLOCK(&channelvars);
07016 while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
07017 ast_free(var);
07018 }
07019 AST_RWLIST_UNLOCK(&channelvars);
07020 }
07021
07022 int init_manager(void)
07023 {
07024 return __init_manager(0);
07025 }
07026
07027 int reload_manager(void)
07028 {
07029 return __init_manager(1);
07030 }
07031
07032 int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
07033 {
07034 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
07035
07036 return 0;
07037 }
07038
07039 int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
07040 {
07041 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
07042 }
07043
07044 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
07045 {
07046 struct ast_datastore *datastore = NULL;
07047
07048 if (info == NULL)
07049 return NULL;
07050
07051 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
07052 if (datastore->info != info) {
07053 continue;
07054 }
07055
07056 if (uid == NULL) {
07057
07058 break;
07059 }
07060
07061 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
07062
07063 break;
07064 }
07065 }
07066 AST_LIST_TRAVERSE_SAFE_END;
07067
07068 return datastore;
07069 }