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