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