I would like to get feedback on this and see if people is confortable with these clang rules. Right now is using the "llvm" style increasing the line length from 80 to 120 given that coturn is using long lines often. Co-authored-by: Pavel Punsky <eakraly@users.noreply.github.com>
3796 lines
132 KiB
C
3796 lines
132 KiB
C
/*
|
|
* Copyright (C) 2011, 2012, 2013 Citrix Systems
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#if defined(_MSC_VER)
|
|
#include <direct.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(__unix__) || defined(unix) || defined(__APPLE__)
|
|
#include <ifaddrs.h>
|
|
#include <libgen.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
|
|
#include <getopt.h>
|
|
#include <locale.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include "libtelnet.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <event2/buffer.h>
|
|
#include <event2/bufferevent.h>
|
|
#include <event2/http.h>
|
|
#include <event2/listener.h>
|
|
|
|
#include "mainrelay.h"
|
|
#include "userdb.h"
|
|
|
|
#include "ns_turn_utils.h"
|
|
|
|
#include "ns_turn_maps.h"
|
|
#include "ns_turn_server.h"
|
|
|
|
#include "apputils.h"
|
|
|
|
#include "turn_admin_server.h"
|
|
|
|
#include "http_server.h"
|
|
|
|
#include "dbdrivers/dbdriver.h"
|
|
|
|
#include "tls_listener.h"
|
|
|
|
///////////////////////////////
|
|
|
|
struct admin_server adminserver;
|
|
|
|
int use_cli = 1;
|
|
|
|
ioa_addr cli_addr;
|
|
int cli_addr_set = 0;
|
|
|
|
int cli_port = CLI_DEFAULT_PORT;
|
|
|
|
char cli_password[CLI_PASSWORD_LENGTH] = "";
|
|
|
|
int cli_max_output_sessions = DEFAULT_CLI_MAX_OUTPUT_SESSIONS;
|
|
|
|
int use_web_admin = 0;
|
|
|
|
ioa_addr web_admin_addr;
|
|
int web_admin_addr_set = 0;
|
|
|
|
int web_admin_port = WEB_ADMIN_DEFAULT_PORT;
|
|
|
|
///////////////////////////////
|
|
|
|
struct cli_session {
|
|
evutil_socket_t fd;
|
|
int auth_completed;
|
|
size_t cmds;
|
|
struct bufferevent *bev;
|
|
ioa_addr addr;
|
|
telnet_t *ts;
|
|
FILE *f;
|
|
char realm[STUN_MAX_REALM_SIZE + 1];
|
|
char origin[STUN_MAX_ORIGIN_SIZE + 1];
|
|
realm_params_t *rp;
|
|
};
|
|
|
|
///////////////////////////////
|
|
|
|
#define CLI_PASSWORD_TRY_NUMBER (5)
|
|
|
|
static const char *CLI_HELP_STR[] = {"",
|
|
" ?, h, help - print this text",
|
|
"",
|
|
" quit, q, exit, bye - end CLI session",
|
|
"",
|
|
" stop, shutdown, halt - shutdown TURN Server",
|
|
"",
|
|
" pc - print configuration",
|
|
"",
|
|
" sr <realm> - set CLI session realm",
|
|
"",
|
|
" ur - unset CLI session realm",
|
|
"",
|
|
" so <origin> - set CLI session origin",
|
|
"",
|
|
" uo - unset CLI session origin",
|
|
"",
|
|
" tc <param-name> - toggle a configuration parameter",
|
|
" (see pc command output for togglable param names)",
|
|
"",
|
|
" cc <param-name> <param-value> - change a configuration parameter",
|
|
" (see pc command output for changeable param names)",
|
|
"",
|
|
" ps [username] - print sessions, with optional exact user match",
|
|
"",
|
|
" psp <usernamestr> - print sessions, with partial user string match",
|
|
"",
|
|
" psd <file-name> - dump ps command output into file on the TURN server system",
|
|
"",
|
|
" pu [udp|tcp|dtls|tls]- print current users",
|
|
"",
|
|
" lr - log reset",
|
|
"",
|
|
" aas ip[:port} - add an alternate server reference",
|
|
" das ip[:port] - delete an alternate server reference",
|
|
" atas ip[:port] - add a TLS alternate server reference",
|
|
" dtas ip[:port] - delete a TLS alternate server reference",
|
|
"",
|
|
" cs <session-id> - cancel session, forcefully",
|
|
"",
|
|
NULL};
|
|
|
|
static const char *CLI_GREETING_STR[] = {"TURN Server", TURN_SOFTWARE, NULL};
|
|
|
|
static char CLI_CURSOR[] = "> ";
|
|
|
|
static const telnet_telopt_t cli_telopts[] = {
|
|
{TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DONT}, {TELNET_TELOPT_TTYPE, TELNET_WONT, TELNET_DONT},
|
|
{TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DONT}, {TELNET_TELOPT_ZMP, TELNET_WONT, TELNET_DONT},
|
|
{TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DONT}, {TELNET_TELOPT_BINARY, TELNET_WONT, TELNET_DONT},
|
|
{TELNET_TELOPT_NAWS, TELNET_WONT, TELNET_DONT}, {-1, 0, 0}};
|
|
|
|
struct toggleable_command {
|
|
const char *cmd;
|
|
vintp data;
|
|
};
|
|
|
|
struct toggleable_command tcmds[] = {{"stale-nonce", &turn_params.stale_nonce},
|
|
{"stun-only", &turn_params.stun_only},
|
|
{"no-stun", &turn_params.no_stun},
|
|
{"secure-stun", &turn_params.secure_stun},
|
|
{"no-udp-relay", &turn_params.no_udp_relay},
|
|
{"no-tcp-relay", &turn_params.no_tcp_relay},
|
|
{"no-multicast-peers", &turn_params.no_multicast_peers},
|
|
{"allow-loopback-peers", &turn_params.allow_loopback_peers},
|
|
{"mobility", &turn_params.mobility},
|
|
{NULL, NULL}};
|
|
|
|
///////////////////////////////
|
|
|
|
static void myprintf(struct cli_session *cs, const char *format, ...) {
|
|
if (cs && format) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
if (cs->f) {
|
|
vfprintf(cs->f, format, args);
|
|
} else {
|
|
telnet_vprintf(cs->ts, format, args);
|
|
}
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
static void log_reset(struct cli_session *cs) {
|
|
if (cs) {
|
|
reset_rtpprintf();
|
|
myprintf(cs, " log reset done\n");
|
|
}
|
|
}
|
|
|
|
static void print_str_array(struct cli_session *cs, const char **sa) {
|
|
if (cs && sa) {
|
|
int i = 0;
|
|
while (sa[i]) {
|
|
myprintf(cs, "%s\n", sa[i]);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const char *get_flag(int val) {
|
|
if (val)
|
|
return "ON";
|
|
return "OFF";
|
|
}
|
|
|
|
static void cli_print_flag(struct cli_session *cs, int flag, const char *name, int changeable) {
|
|
if (cs && cs->ts && name) {
|
|
const char *sc = "";
|
|
if (changeable)
|
|
sc = " (*)";
|
|
myprintf(cs, " %s: %s%s\n", name, get_flag(flag), sc);
|
|
}
|
|
}
|
|
|
|
static void cli_print_uint(struct cli_session *cs, unsigned long value, const char *name, int changeable) {
|
|
if (cs && cs->ts && name) {
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
myprintf(cs, " %s: %lu%s\n", name, value, sc);
|
|
}
|
|
}
|
|
|
|
static void cli_print_str(struct cli_session *cs, const char *value, const char *name, int changeable) {
|
|
if (cs && cs->ts && name && value) {
|
|
if (value[0] == 0)
|
|
value = "empty";
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
myprintf(cs, " %s: %s%s\n", name, value, sc);
|
|
}
|
|
}
|
|
|
|
static void cli_print_addr(struct cli_session *cs, ioa_addr *value, int use_port, const char *name, int changeable) {
|
|
if (cs && cs->ts && name && value) {
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
char s[256];
|
|
if (!use_port)
|
|
addr_to_string_no_port(value, (uint8_t *)s);
|
|
else
|
|
addr_to_string(value, (uint8_t *)s);
|
|
myprintf(cs, " %s: %s%s\n", name, s, sc);
|
|
}
|
|
}
|
|
|
|
static void cli_print_addr_list(struct cli_session *cs, turn_server_addrs_list_t *value, int use_port, const char *name,
|
|
int changeable) {
|
|
if (cs && cs->ts && name && value && value->size && value->addrs) {
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
char s[256];
|
|
size_t i;
|
|
for (i = 0; i < value->size; i++) {
|
|
if (!use_port)
|
|
addr_to_string_no_port(&(value->addrs[i]), (uint8_t *)s);
|
|
else
|
|
addr_to_string(&(value->addrs[i]), (uint8_t *)s);
|
|
myprintf(cs, " %s: %s%s\n", name, s, sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cli_print_str_array(struct cli_session *cs, char **value, size_t sz, const char *name, int changeable) {
|
|
if (cs && cs->ts && name && value && sz) {
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
size_t i;
|
|
for (i = 0; i < sz; i++) {
|
|
if (value[i])
|
|
myprintf(cs, " %s: %s%s\n", name, value[i], sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cli_print_ip_range_list(struct cli_session *cs, ip_range_list_t *value, const char *name, int changeable) {
|
|
if (cs && cs->ts && name && value && value->ranges_number && value->rs) {
|
|
const char *sc = "";
|
|
if (changeable == 1)
|
|
sc = " (*)";
|
|
else if (changeable == 2)
|
|
sc = " (**)";
|
|
size_t i;
|
|
for (i = 0; i < value->ranges_number; ++i) {
|
|
if (value->rs[i].realm[0]) {
|
|
if (cs->realm[0] && strcmp(cs->realm, value->rs[i].realm)) {
|
|
continue;
|
|
} else {
|
|
myprintf(cs, " %s: %s (%s)%s\n", name, value->rs[i].str, value->rs[i].realm, sc);
|
|
}
|
|
} else {
|
|
myprintf(cs, " %s: %s%s\n", name, value->rs[i].str, sc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void toggle_cli_param(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn) {
|
|
|
|
int i = 0;
|
|
|
|
while (tcmds[i].cmd && tcmds[i].data) {
|
|
if (strcmp(tcmds[i].cmd, pn) == 0) {
|
|
*(tcmds[i].data) = !(*(tcmds[i].data));
|
|
cli_print_flag(cs, *(tcmds[i].data), tcmds[i].cmd, 0);
|
|
return;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
myprintf(cs, "\n");
|
|
myprintf(cs, " Error: unknown or constant parameter: %s.\n", pn);
|
|
myprintf(cs, " You can toggle only the following parameters:\n");
|
|
myprintf(cs, "\n");
|
|
|
|
i = 0;
|
|
|
|
while (tcmds[i].cmd && tcmds[i].data) {
|
|
cli_print_flag(cs, *(tcmds[i].data), tcmds[i].cmd, 0);
|
|
++i;
|
|
}
|
|
|
|
myprintf(cs, "\n");
|
|
}
|
|
}
|
|
|
|
static void change_cli_param(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn) {
|
|
|
|
if (strstr(pn, "total-quota") == pn) {
|
|
turn_params.total_quota = atoi(pn + strlen("total-quota"));
|
|
cli_print_uint(cs, (unsigned long)turn_params.total_quota, "total-quota", 2);
|
|
return;
|
|
} else if (strstr(pn, "user-quota") == pn) {
|
|
turn_params.user_quota = atoi(pn + strlen("user-quota"));
|
|
cli_print_uint(cs, (unsigned long)turn_params.user_quota, "user-quota", 2);
|
|
return;
|
|
} else if (strstr(pn, "max-bps") == pn) {
|
|
set_max_bps((band_limit_t)strtoul(pn + strlen("max-bps"), NULL, 10));
|
|
cli_print_uint(cs, (unsigned long)get_max_bps(), "max-bps", 2);
|
|
return;
|
|
} else if (strstr(pn, "bps-capacity") == pn) {
|
|
set_bps_capacity((band_limit_t)strtoul(pn + strlen("bps-capacity"), NULL, 10));
|
|
cli_print_uint(cs, (unsigned long)get_bps_capacity(), "bps-capacity", 2);
|
|
return;
|
|
} else if (strstr(pn, "cli-max-output-sessions") == pn) {
|
|
cli_max_output_sessions = atoi(pn + strlen("cli-max-output-sessions"));
|
|
cli_print_uint(cs, (unsigned long)cli_max_output_sessions, "cli-max-output-sessions", 2);
|
|
return;
|
|
}
|
|
|
|
myprintf(cs, "\n");
|
|
myprintf(cs, " Error: unknown or constant parameter: %s.\n", pn);
|
|
myprintf(cs, "\n");
|
|
}
|
|
}
|
|
|
|
struct ps_arg {
|
|
struct cli_session *cs;
|
|
size_t counter;
|
|
turn_time_t ct;
|
|
const char *username;
|
|
const char *pname;
|
|
int exact_match;
|
|
ur_string_map *users;
|
|
size_t *user_counters;
|
|
char **user_names;
|
|
size_t users_number;
|
|
};
|
|
|
|
static int print_session(ur_map_key_type key, ur_map_value_type value, void *arg) {
|
|
if (key && value && arg) {
|
|
struct ps_arg *csarg = (struct ps_arg *)arg;
|
|
struct cli_session *cs = csarg->cs;
|
|
struct turn_session_info *tsi = (struct turn_session_info *)value;
|
|
|
|
if (cs->realm[0] && strcmp(cs->realm, tsi->realm))
|
|
return 0;
|
|
|
|
if (cs->origin[0] && strcmp(cs->origin, tsi->origin))
|
|
return 0;
|
|
|
|
if (csarg->users) {
|
|
|
|
const char *pn = csarg->pname;
|
|
if (pn[0]) {
|
|
if (!strcmp(pn, "TLS") || !strcmp(pn, "tls") || !strcmp(pn, "Tls")) {
|
|
if ((tsi->client_protocol != TLS_SOCKET) && (tsi->client_protocol != TLS_SCTP_SOCKET))
|
|
return 0;
|
|
} else if (!strcmp(pn, "DTLS") || !strcmp(pn, "dtls") || !strcmp(pn, "Dtls")) {
|
|
if (tsi->client_protocol != DTLS_SOCKET)
|
|
return 0;
|
|
} else if (!strcmp(pn, "TCP") || !strcmp(pn, "tcp") || !strcmp(pn, "Tcp")) {
|
|
if ((tsi->client_protocol != TCP_SOCKET) && (tsi->client_protocol != SCTP_SOCKET))
|
|
return 0;
|
|
} else if (!strcmp(pn, "UDP") || !strcmp(pn, "udp") || !strcmp(pn, "Udp")) {
|
|
if (tsi->client_protocol != UDP_SOCKET)
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ur_string_map_value_type value;
|
|
if (!ur_string_map_get(csarg->users, (ur_string_map_key_type)(char *)tsi->username, &value)) {
|
|
value = (ur_string_map_value_type)csarg->users_number;
|
|
csarg->users_number += 1;
|
|
csarg->user_counters = (size_t *)realloc(csarg->user_counters, csarg->users_number * sizeof(size_t));
|
|
csarg->user_names = (char **)realloc(csarg->user_names, csarg->users_number * sizeof(char *));
|
|
csarg->user_names[(size_t)value] = strdup((char *)tsi->username);
|
|
csarg->user_counters[(size_t)value] = 0;
|
|
ur_string_map_put(csarg->users, (ur_string_map_key_type)(char *)tsi->username, value);
|
|
}
|
|
csarg->user_counters[(size_t)value] += 1;
|
|
} else {
|
|
if (csarg->username[0]) {
|
|
if (csarg->exact_match) {
|
|
if (strcmp((char *)tsi->username, csarg->username))
|
|
return 0;
|
|
} else {
|
|
if (!strstr((char *)tsi->username, csarg->username))
|
|
return 0;
|
|
}
|
|
}
|
|
if (cs->f || (unsigned long)csarg->counter < (unsigned long)cli_max_output_sessions) {
|
|
myprintf(cs, "\n");
|
|
myprintf(cs, " %lu) id=%018llu, user <%s>:\n", (unsigned long)(csarg->counter + 1),
|
|
(unsigned long long)tsi->id, tsi->username);
|
|
if (tsi->realm[0])
|
|
myprintf(cs, " realm: %s\n", tsi->realm);
|
|
if (tsi->origin[0])
|
|
myprintf(cs, " origin: %s\n", tsi->origin);
|
|
if (turn_time_before(csarg->ct, tsi->start_time)) {
|
|
myprintf(cs, " started: undefined time\n");
|
|
} else {
|
|
myprintf(cs, " started %lu secs ago\n", (unsigned long)(csarg->ct - tsi->start_time));
|
|
}
|
|
if (turn_time_before(tsi->expiration_time, csarg->ct)) {
|
|
myprintf(cs, " expired\n");
|
|
} else {
|
|
myprintf(cs, " expiring in %lu secs\n", (unsigned long)(tsi->expiration_time - csarg->ct));
|
|
}
|
|
myprintf(cs, " client protocol %s, relay protocol %s\n", socket_type_name(tsi->client_protocol),
|
|
socket_type_name(tsi->peer_protocol));
|
|
{
|
|
if (!tsi->local_addr_data.saddr[0])
|
|
addr_to_string(&(tsi->local_addr_data.addr), (uint8_t *)tsi->local_addr_data.saddr);
|
|
if (!tsi->remote_addr_data.saddr[0])
|
|
addr_to_string(&(tsi->remote_addr_data.addr), (uint8_t *)tsi->remote_addr_data.saddr);
|
|
if (!tsi->relay_addr_data_ipv4.saddr[0])
|
|
addr_to_string(&(tsi->relay_addr_data_ipv4.addr), (uint8_t *)tsi->relay_addr_data_ipv4.saddr);
|
|
if (!tsi->relay_addr_data_ipv6.saddr[0])
|
|
addr_to_string(&(tsi->relay_addr_data_ipv6.addr), (uint8_t *)tsi->relay_addr_data_ipv6.saddr);
|
|
myprintf(cs, " client addr %s, server addr %s\n", tsi->remote_addr_data.saddr,
|
|
tsi->local_addr_data.saddr);
|
|
if (tsi->relay_addr_data_ipv4.saddr[0]) {
|
|
myprintf(cs, " relay addr %s\n", tsi->relay_addr_data_ipv4.saddr);
|
|
}
|
|
if (tsi->relay_addr_data_ipv6.saddr[0]) {
|
|
myprintf(cs, " relay addr %s\n", tsi->relay_addr_data_ipv6.saddr);
|
|
}
|
|
}
|
|
myprintf(cs, " fingerprints enforced: %s\n", get_flag(tsi->enforce_fingerprints));
|
|
myprintf(cs, " mobile: %s\n", get_flag(tsi->is_mobile));
|
|
if (tsi->tls_method[0]) {
|
|
myprintf(cs, " TLS method: %s\n", tsi->tls_method);
|
|
myprintf(cs, " TLS cipher: %s\n", tsi->tls_cipher);
|
|
}
|
|
if (tsi->bps)
|
|
myprintf(cs, " Max throughput: %lu bytes per second\n", (unsigned long)tsi->bps);
|
|
myprintf(cs, " usage: rp=%lu, rb=%lu, sp=%lu, sb=%lu\n", (unsigned long)(tsi->received_packets),
|
|
(unsigned long)(tsi->received_bytes), (unsigned long)(tsi->sent_packets),
|
|
(unsigned long)(tsi->sent_bytes));
|
|
myprintf(cs, " rate: r=%lu, s=%lu, total=%lu (bytes per sec)\n", (unsigned long)(tsi->received_rate),
|
|
(unsigned long)(tsi->sent_rate), (unsigned long)(tsi->total_rate));
|
|
if (tsi->main_peers_size) {
|
|
myprintf(cs, " peers:\n");
|
|
size_t i;
|
|
for (i = 0; i < tsi->main_peers_size; ++i) {
|
|
if (!(tsi->main_peers_data[i].saddr[0]))
|
|
addr_to_string(&(tsi->main_peers_data[i].addr), (uint8_t *)tsi->main_peers_data[i].saddr);
|
|
myprintf(cs, " %s\n", tsi->main_peers_data[i].saddr);
|
|
}
|
|
if (tsi->extra_peers_size && tsi->extra_peers_data) {
|
|
for (i = 0; i < tsi->extra_peers_size; ++i) {
|
|
if (!(tsi->extra_peers_data[i].saddr[0]))
|
|
addr_to_string(&(tsi->extra_peers_data[i].addr), (uint8_t *)tsi->extra_peers_data[i].saddr);
|
|
myprintf(cs, " %s\n", tsi->extra_peers_data[i].saddr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
csarg->counter += 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void cancel_session(struct cli_session *cs, const char *ssid) {
|
|
if (cs && cs->ts && ssid && *ssid) {
|
|
turnsession_id sid = strtoull(ssid, NULL, 10);
|
|
send_session_cancellation_to_relay(sid);
|
|
}
|
|
}
|
|
|
|
static void print_sessions(struct cli_session *cs, const char *pn, int exact_match, int print_users) {
|
|
if (cs && cs->ts && pn) {
|
|
|
|
while (pn[0] == ' ')
|
|
++pn;
|
|
if (pn[0] == '*')
|
|
++pn;
|
|
|
|
const char *uname = "";
|
|
if (!print_users) {
|
|
uname = pn;
|
|
pn = "";
|
|
}
|
|
|
|
struct ps_arg arg = {cs, 0, 0, uname, pn, exact_match, NULL, NULL, NULL, 0};
|
|
|
|
arg.ct = turn_time();
|
|
|
|
if (print_users) {
|
|
arg.users = ur_string_map_create(NULL);
|
|
}
|
|
|
|
ur_map_foreach_arg(adminserver.sessions, (foreachcb_arg_type)print_session, &arg);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
if (!print_users && !(cs->f)) {
|
|
if ((unsigned long)arg.counter > (unsigned long)cli_max_output_sessions) {
|
|
myprintf(cs, "...\n");
|
|
myprintf(cs, "\n");
|
|
}
|
|
} else if (arg.user_counters && arg.user_names) {
|
|
size_t i;
|
|
for (i = 0; i < arg.users_number; ++i) {
|
|
if (arg.user_names[i]) {
|
|
myprintf(cs, " user: <%s>, %lu sessions\n", arg.user_names[i], (unsigned long)arg.user_counters[i]);
|
|
}
|
|
}
|
|
myprintf(cs, "\n");
|
|
}
|
|
|
|
{
|
|
char ts[1025];
|
|
snprintf(ts, sizeof(ts), " Total sessions");
|
|
if (cs->realm[0]) {
|
|
snprintf(ts + strlen(ts), sizeof(ts) - strlen(ts), " for realm %s", cs->realm);
|
|
if (cs->origin[0])
|
|
snprintf(ts + strlen(ts), sizeof(ts) - strlen(ts), " and for origin %s", cs->origin);
|
|
} else {
|
|
if (cs->origin[0])
|
|
snprintf(ts + strlen(ts), sizeof(ts) - strlen(ts), " for origin %s", cs->origin);
|
|
}
|
|
snprintf(ts + strlen(ts), sizeof(ts) - strlen(ts), ": %lu", (unsigned long)arg.counter);
|
|
myprintf(cs, "%s\n", ts);
|
|
myprintf(cs, "\n");
|
|
}
|
|
|
|
if (!print_users && !(cs->f)) {
|
|
if ((unsigned long)arg.counter > (unsigned long)cli_max_output_sessions) {
|
|
myprintf(cs, " Warning: too many output sessions, more than the\n");
|
|
myprintf(cs, " current value of cli-max-output-sessions CLI parameter.\n");
|
|
myprintf(cs, " Refine your request or increase cli-max-output-sessions value.\n");
|
|
myprintf(cs, "\n");
|
|
}
|
|
}
|
|
|
|
if (arg.user_counters)
|
|
free(arg.user_counters);
|
|
if (arg.user_names) {
|
|
size_t i;
|
|
for (i = 0; i < arg.users_number; ++i) {
|
|
if (arg.user_names[i])
|
|
free(arg.user_names[i]);
|
|
}
|
|
free(arg.user_names);
|
|
}
|
|
if (arg.users)
|
|
ur_string_map_free(&arg.users);
|
|
}
|
|
}
|
|
|
|
static void cli_print_configuration(struct cli_session *cs) {
|
|
if (cs) {
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_flag(cs, turn_params.verbose, "verbose", 0);
|
|
cli_print_flag(cs, turn_params.turn_daemon, "daemon process", 0);
|
|
cli_print_flag(cs, turn_params.stale_nonce, "stale-nonce", 1);
|
|
cli_print_flag(cs, turn_params.stun_only, "stun-only", 1);
|
|
cli_print_flag(cs, turn_params.no_stun, "no-stun", 1);
|
|
cli_print_flag(cs, turn_params.secure_stun, "secure-stun", 1);
|
|
cli_print_flag(cs, turn_params.do_not_use_config_file, "do-not-use-config-file", 0);
|
|
cli_print_flag(cs, turn_params.rfc5780, "RFC5780 support", 0);
|
|
cli_print_uint(cs, (unsigned int)turn_params.net_engine_version, "net engine version", 0);
|
|
cli_print_str(cs, turn_params.net_engine_version_txt[(int)turn_params.net_engine_version], "net engine", 0);
|
|
cli_print_flag(cs, turn_params.fingerprint, "enforce fingerprints", 0);
|
|
cli_print_flag(cs, turn_params.mobility, "mobility", 1);
|
|
cli_print_flag(cs, turn_params.udp_self_balance, "udp-self-balance", 0);
|
|
cli_print_str(cs, turn_params.pidfile, "pidfile", 0);
|
|
#if defined(WINDOWS)
|
|
// TODO: implement it!!!
|
|
#else
|
|
cli_print_uint(cs, (unsigned long)getuid(), "process user ID", 0);
|
|
cli_print_uint(cs, (unsigned long)getgid(), "process group ID", 0);
|
|
#endif
|
|
|
|
{
|
|
char wd[1025];
|
|
if (getcwd(wd, sizeof(wd) - 1)) {
|
|
cli_print_str(cs, wd, "process dir", 0);
|
|
}
|
|
}
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
if (turn_params.cipher_list[0])
|
|
cli_print_str(cs, turn_params.cipher_list, "cipher-list", 0);
|
|
else
|
|
cli_print_str(cs, DEFAULT_CIPHER_LIST, "cipher-list", 0);
|
|
|
|
cli_print_str(cs, turn_params.ec_curve_name, "ec-curve-name", 0);
|
|
{
|
|
if (turn_params.dh_key_size == DH_CUSTOM)
|
|
cli_print_str(cs, turn_params.dh_file, "dh-file", 0);
|
|
else {
|
|
unsigned int dh_key_length = 1066;
|
|
if (turn_params.dh_key_size == DH_566)
|
|
dh_key_length = 566;
|
|
else if (turn_params.dh_key_size == DH_2066)
|
|
dh_key_length = 2066;
|
|
cli_print_uint(cs, (unsigned long)dh_key_length, "DH-key-length", 0);
|
|
}
|
|
}
|
|
|
|
cli_print_str(cs, turn_params.ca_cert_file, "Certificate Authority file", 0);
|
|
cli_print_str(cs, turn_params.cert_file, "Certificate file", 0);
|
|
cli_print_str(cs, turn_params.pkey_file, "Private Key file", 0);
|
|
|
|
cli_print_str_array(cs, turn_params.listener.addrs, turn_params.listener.addrs_number, "Listener addr", 0);
|
|
|
|
if (turn_params.listener_ifname[0])
|
|
cli_print_str(cs, turn_params.listener_ifname, "listener-ifname", 0);
|
|
|
|
cli_print_flag(cs, turn_params.no_udp, "no-udp", 0);
|
|
cli_print_flag(cs, turn_params.no_tcp, "no-tcp", 0);
|
|
cli_print_flag(cs, turn_params.no_dtls, "no-dtls", 0);
|
|
cli_print_flag(cs, turn_params.no_tls, "no-tls", 0);
|
|
|
|
cli_print_flag(cs, (!turn_params.no_tlsv1 && !turn_params.no_tls), "TLSv1.0", 0);
|
|
cli_print_flag(cs, (!turn_params.no_tlsv1_1 && !turn_params.no_tls), "TLSv1.1", 0);
|
|
cli_print_flag(cs, (!turn_params.no_tlsv1_2 && !turn_params.no_tls), "TLSv1.2", 0);
|
|
|
|
cli_print_uint(cs, (unsigned long)turn_params.listener_port, "listener-port", 0);
|
|
cli_print_uint(cs, (unsigned long)turn_params.tls_listener_port, "tls-listener-port", 0);
|
|
cli_print_uint(cs, (unsigned long)turn_params.alt_listener_port, "alt-listener-port", 0);
|
|
cli_print_uint(cs, (unsigned long)turn_params.alt_tls_listener_port, "alt-tls-listener-port", 0);
|
|
|
|
cli_print_addr(cs, turn_params.external_ip, 0, "External public IP", 0);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_addr_list(cs, &turn_params.aux_servers_list, 1, "Aux server", 0);
|
|
cli_print_addr_list(cs, &turn_params.alternate_servers_list, 1, "Alternate server", 0);
|
|
cli_print_addr_list(cs, &turn_params.tls_alternate_servers_list, 1, "TLS alternate server", 0);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_str_array(cs, turn_params.relay_addrs, turn_params.relays_number, "Relay addr", 0);
|
|
|
|
if (turn_params.relay_ifname[0])
|
|
cli_print_str(cs, turn_params.relay_ifname, "relay-ifname", 0);
|
|
|
|
cli_print_flag(cs, turn_params.server_relay, "server-relay", 0);
|
|
|
|
cli_print_flag(cs, turn_params.no_udp_relay, "no-udp-relay", 1);
|
|
cli_print_flag(cs, turn_params.no_tcp_relay, "no-tcp-relay", 1);
|
|
|
|
cli_print_uint(cs, (unsigned long)turn_params.min_port, "min-port", 0);
|
|
cli_print_uint(cs, (unsigned long)turn_params.max_port, "max-port", 0);
|
|
|
|
cli_print_ip_range_list(cs, &turn_params.ip_whitelist, "Whitelist IP (static)", 0);
|
|
{
|
|
ip_range_list_t *l = get_ip_list("allowed");
|
|
cli_print_ip_range_list(cs, l, "Whitelist IP (dynamic)", 0);
|
|
ip_list_free(l);
|
|
}
|
|
|
|
cli_print_ip_range_list(cs, &turn_params.ip_blacklist, "Blacklist IP (static)", 0);
|
|
{
|
|
ip_range_list_t *l = get_ip_list("denied");
|
|
cli_print_ip_range_list(cs, l, "Blacklist IP (dynamic)", 0);
|
|
ip_list_free(l);
|
|
}
|
|
|
|
cli_print_flag(cs, turn_params.no_multicast_peers, "no-multicast-peers", 1);
|
|
cli_print_flag(cs, turn_params.allow_loopback_peers, "allow-loopback-peers", 1);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
if (turn_params.default_users_db.persistent_users_db.userdb[0]) {
|
|
switch (turn_params.default_users_db.userdb_type) {
|
|
#if !defined(TURN_NO_SQLITE)
|
|
case TURN_USERDB_TYPE_SQLITE:
|
|
cli_print_str(cs, "SQLite", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
case TURN_USERDB_TYPE_PQ:
|
|
cli_print_str(cs, "Postgres", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
case TURN_USERDB_TYPE_MYSQL:
|
|
cli_print_str(cs, "MySQL/MariaDB", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
case TURN_USERDB_TYPE_MONGO:
|
|
cli_print_str(cs, "MongoDB", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
case TURN_USERDB_TYPE_REDIS:
|
|
cli_print_str(cs, "redis", "DB type", 0);
|
|
break;
|
|
#endif
|
|
default:
|
|
cli_print_str(cs, "unknown", "DB type", 0);
|
|
};
|
|
cli_print_str(cs, turn_params.default_users_db.persistent_users_db.userdb, "DB", 0);
|
|
} else {
|
|
cli_print_str(cs, "none", "DB type", 0);
|
|
cli_print_str(cs, "none", "DB", 0);
|
|
}
|
|
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
if (turn_params.use_redis_statsdb && turn_params.redis_statsdb.connection_string[0])
|
|
cli_print_str(cs, turn_params.redis_statsdb.connection_string, "Redis Statistics DB", 0);
|
|
#endif
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
{
|
|
char *rn = get_realm(NULL)->options.name;
|
|
if (rn[0])
|
|
cli_print_str(cs, rn, "Default realm", 0);
|
|
}
|
|
if (cs->realm[0])
|
|
cli_print_str(cs, cs->realm, "CLI session realm", 0);
|
|
else
|
|
cli_print_str(cs, get_realm(NULL)->options.name, "CLI session realm", 0);
|
|
if (cs->origin[0])
|
|
cli_print_str(cs, cs->origin, "CLI session origin", 0);
|
|
if (turn_params.ct == TURN_CREDENTIALS_LONG_TERM)
|
|
cli_print_flag(cs, 1, "Long-term authorization mechanism", 0);
|
|
else
|
|
cli_print_flag(cs, 1, "Anonymous credentials", 0);
|
|
cli_print_flag(cs, turn_params.use_auth_secret_with_timestamp, "TURN REST API support", 0);
|
|
if (turn_params.use_auth_secret_with_timestamp && turn_params.rest_api_separator)
|
|
cli_print_uint(cs, turn_params.rest_api_separator, "TURN REST API separator ASCII number", 0);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_uint(cs, (unsigned long)cs->rp->status.total_current_allocs, "total-current-allocs", 0);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_uint(cs, (unsigned long)turn_params.total_quota, "Default total-quota", 2);
|
|
cli_print_uint(cs, (unsigned long)turn_params.user_quota, "Default user-quota", 2);
|
|
cli_print_uint(cs, (unsigned long)get_bps_capacity(), "Total server bps-capacity", 2);
|
|
cli_print_uint(cs, (unsigned long)get_bps_capacity_allocated(), "Allocated bps-capacity", 0);
|
|
cli_print_uint(cs, (unsigned long)get_max_bps(), "Default max-bps", 2);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_uint(cs, (unsigned long)cs->rp->options.perf_options.total_quota, "current realm total-quota", 0);
|
|
cli_print_uint(cs, (unsigned long)cs->rp->options.perf_options.user_quota, "current realm user-quota", 0);
|
|
cli_print_uint(cs, (unsigned long)cs->rp->options.perf_options.max_bps, "current realm max-bps", 0);
|
|
|
|
myprintf(cs, "\n");
|
|
|
|
cli_print_uint(cs, (unsigned long)cli_max_output_sessions, "cli-max-output-sessions", 2);
|
|
|
|
{
|
|
myprintf(cs, "\n");
|
|
const char *str = " (Note 1: parameters with (*) are toggleable)";
|
|
myprintf(cs, "%s\n", str);
|
|
myprintf(cs, "\n");
|
|
str = " (Note 2: parameters with (**) are changeable)";
|
|
myprintf(cs, "%s\n", str);
|
|
myprintf(cs, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void close_cli_session(struct cli_session *cs);
|
|
|
|
static int run_cli_output(struct cli_session *cs, const char *buf, unsigned int len) {
|
|
if (cs && buf && len) {
|
|
if (bufferevent_write(cs->bev, buf, len) < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void close_cli_session(struct cli_session *cs) {
|
|
if (cs) {
|
|
|
|
addr_debug_print(adminserver.verbose, &(cs->addr), "CLI session disconnected from");
|
|
|
|
if (cs->ts) {
|
|
telnet_free(cs->ts);
|
|
cs->ts = NULL;
|
|
}
|
|
|
|
BUFFEREVENT_FREE(cs->bev);
|
|
|
|
if (cs->fd >= 0) {
|
|
close(cs->fd);
|
|
cs->fd = -1;
|
|
}
|
|
|
|
free(cs);
|
|
}
|
|
}
|
|
|
|
static void type_cli_cursor(struct cli_session *cs) {
|
|
if (cs && (cs->bev)) {
|
|
myprintf(cs, "%s", CLI_CURSOR);
|
|
}
|
|
}
|
|
|
|
static void cli_add_alternate_server(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn && *pn) {
|
|
add_alternate_server(pn);
|
|
}
|
|
}
|
|
|
|
static void cli_add_tls_alternate_server(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn && *pn) {
|
|
add_tls_alternate_server(pn);
|
|
}
|
|
}
|
|
|
|
static void cli_del_alternate_server(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn && *pn) {
|
|
del_alternate_server(pn);
|
|
}
|
|
}
|
|
|
|
static void cli_del_tls_alternate_server(struct cli_session *cs, const char *pn) {
|
|
if (cs && cs->ts && pn && *pn) {
|
|
del_tls_alternate_server(pn);
|
|
}
|
|
}
|
|
|
|
static int run_cli_input(struct cli_session *cs, const char *buf0, unsigned int len) {
|
|
int ret = 0;
|
|
|
|
if (cs && buf0 && cs->ts && cs->bev) {
|
|
|
|
char *buf = (char *)malloc(len + 1);
|
|
memcpy(buf, buf0, len);
|
|
buf[len] = 0;
|
|
|
|
char *cmd = buf;
|
|
|
|
while ((cmd[0] == ' ') || (cmd[0] == '\t'))
|
|
++cmd;
|
|
|
|
size_t sl = strlen(cmd);
|
|
|
|
while (sl) {
|
|
char c = cmd[sl - 1];
|
|
if ((c == 10) || (c == 13)) {
|
|
cmd[sl - 1] = 0;
|
|
--sl;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sl) {
|
|
cs->cmds += 1;
|
|
if (cli_password[0] && !(cs->auth_completed)) {
|
|
if (check_password(cmd, cli_password)) {
|
|
if (cs->cmds >= CLI_PASSWORD_TRY_NUMBER) {
|
|
addr_debug_print(1, &(cs->addr), "CLI authentication error");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "CLI authentication error\n");
|
|
close_cli_session(cs);
|
|
} else {
|
|
const char *ipwd = "Enter password: ";
|
|
myprintf(cs, "%s\n", ipwd);
|
|
}
|
|
} else {
|
|
cs->auth_completed = 1;
|
|
addr_debug_print(1, &(cs->addr), "CLI authentication success");
|
|
type_cli_cursor(cs);
|
|
}
|
|
} else if ((strcmp(cmd, "bye") == 0) || (strcmp(cmd, "quit") == 0) || (strcmp(cmd, "exit") == 0) ||
|
|
(strcmp(cmd, "q") == 0)) {
|
|
const char *str = "Bye !";
|
|
myprintf(cs, "%s\n", str);
|
|
close_cli_session(cs);
|
|
ret = -1;
|
|
} else if ((strcmp(cmd, "halt") == 0) || (strcmp(cmd, "shutdown") == 0) || (strcmp(cmd, "stop") == 0)) {
|
|
addr_debug_print(1, &(cs->addr), "Shutdown command received from CLI user");
|
|
const char *str = "TURN server is shutting down";
|
|
myprintf(cs, "%s\n", str);
|
|
close_cli_session(cs);
|
|
turn_params.stop_turn_server = 1;
|
|
sleep(10);
|
|
exit(0);
|
|
} else if ((strcmp(cmd, "?") == 0) || (strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
|
|
print_str_array(cs, CLI_GREETING_STR);
|
|
print_str_array(cs, CLI_HELP_STR);
|
|
type_cli_cursor(cs);
|
|
} else if (strcmp(cmd, "pc") == 0) {
|
|
cli_print_configuration(cs);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "tc ") == cmd) {
|
|
toggle_cli_param(cs, cmd + 3);
|
|
} else if (strstr(cmd, "sr ") == cmd) {
|
|
STRCPY(cs->realm, cmd + 3);
|
|
cs->rp = get_realm(cs->realm);
|
|
type_cli_cursor(cs);
|
|
} else if (strcmp(cmd, "ur") == 0) {
|
|
cs->realm[0] = 0;
|
|
cs->rp = get_realm(NULL);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "so ") == cmd) {
|
|
STRCPY(cs->origin, cmd + 3);
|
|
type_cli_cursor(cs);
|
|
} else if (strcmp(cmd, "uo") == 0) {
|
|
cs->origin[0] = 0;
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "tc") == cmd) {
|
|
toggle_cli_param(cs, cmd + 2);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "psp") == cmd) {
|
|
print_sessions(cs, cmd + 3, 0, 0);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "psd") == cmd) {
|
|
cmd += 3;
|
|
while (cmd[0] == ' ')
|
|
++cmd;
|
|
if (!(cmd[0])) {
|
|
const char *str = "You have to provide file name for ps dump\n";
|
|
myprintf(cs, "%s\n", str);
|
|
} else {
|
|
cs->f = fopen(cmd, "w");
|
|
if (!(cs->f)) {
|
|
const char *str = "Cannot open file for writing\n";
|
|
myprintf(cs, "%s\n", str);
|
|
} else {
|
|
print_sessions(cs, "", 1, 0);
|
|
fclose(cs->f);
|
|
cs->f = NULL;
|
|
}
|
|
}
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "pu ") == cmd) {
|
|
print_sessions(cs, cmd + 3, 0, 1);
|
|
type_cli_cursor(cs);
|
|
} else if (!strcmp(cmd, "pu")) {
|
|
print_sessions(cs, cmd + 2, 0, 1);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "ps") == cmd) {
|
|
print_sessions(cs, cmd + 2, 1, 0);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "cs ") == cmd) {
|
|
cancel_session(cs, cmd + 3);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "lr") == cmd) {
|
|
log_reset(cs);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "cc ") == cmd) {
|
|
change_cli_param(cs, cmd + 3);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "cc") == cmd) {
|
|
change_cli_param(cs, cmd + 2);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "aas ") == cmd) {
|
|
cli_add_alternate_server(cs, cmd + 4);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "atas ") == cmd) {
|
|
cli_add_tls_alternate_server(cs, cmd + 5);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "das ") == cmd) {
|
|
cli_del_alternate_server(cs, cmd + 4);
|
|
type_cli_cursor(cs);
|
|
} else if (strstr(cmd, "dtas ") == cmd) {
|
|
cli_del_tls_alternate_server(cs, cmd + 5);
|
|
type_cli_cursor(cs);
|
|
} else {
|
|
const char *str = "Unknown command\n";
|
|
myprintf(cs, "%s\n", str);
|
|
type_cli_cursor(cs);
|
|
}
|
|
} else {
|
|
type_cli_cursor(cs);
|
|
}
|
|
|
|
free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void cli_socket_input_handler_bev(struct bufferevent *bev, void *arg) {
|
|
if (bev && arg) {
|
|
|
|
struct cli_session *cs = (struct cli_session *)arg;
|
|
|
|
if (!(cs->ts))
|
|
return;
|
|
|
|
stun_buffer buf;
|
|
|
|
if (cs->bev) {
|
|
|
|
int len = (int)bufferevent_read(cs->bev, buf.buf, STUN_BUFFER_SIZE - 1);
|
|
if (len < 0) {
|
|
close_cli_session(cs);
|
|
return;
|
|
} else if (len == 0) {
|
|
return;
|
|
}
|
|
|
|
buf.len = len;
|
|
buf.offset = 0;
|
|
buf.buf[len] = 0;
|
|
|
|
telnet_recv(cs->ts, (const char *)buf.buf, (unsigned int)(buf.len));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cli_eventcb_bev(struct bufferevent *bev, short events, void *arg) {
|
|
UNUSED_ARG(bev);
|
|
|
|
if (events & BEV_EVENT_CONNECTED) {
|
|
// Connect okay
|
|
} else if (events & (BEV_EVENT_ERROR | BEV_EVENT_EOF)) {
|
|
if (arg) {
|
|
|
|
struct cli_session *cs = (struct cli_session *)arg;
|
|
|
|
close_cli_session(cs);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cli_telnet_event_handler(telnet_t *telnet, telnet_event_t *event, void *user_data) {
|
|
if (user_data && telnet) {
|
|
|
|
struct cli_session *cs = (struct cli_session *)user_data;
|
|
|
|
switch (event->type) {
|
|
case TELNET_EV_DATA:
|
|
run_cli_input(cs, event->data.buffer, event->data.size);
|
|
break;
|
|
case TELNET_EV_SEND:
|
|
run_cli_output(cs, event->data.buffer, event->data.size);
|
|
break;
|
|
case TELNET_EV_ERROR:
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "TELNET error: %s", event->error.msg);
|
|
break;
|
|
default:;
|
|
};
|
|
}
|
|
}
|
|
|
|
static void cliserver_input_handler(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *sa, int socklen,
|
|
void *arg) {
|
|
UNUSED_ARG(l);
|
|
UNUSED_ARG(arg);
|
|
UNUSED_ARG(socklen);
|
|
|
|
addr_debug_print(adminserver.verbose, (ioa_addr *)sa, "CLI connected to");
|
|
|
|
struct cli_session *clisession = (struct cli_session *)calloc(sizeof(struct cli_session), 1);
|
|
|
|
clisession->rp = get_realm(NULL);
|
|
|
|
set_socket_options_fd(fd, TCP_SOCKET, sa->sa_family);
|
|
|
|
clisession->fd = fd;
|
|
|
|
addr_cpy(&(clisession->addr), (ioa_addr *)sa);
|
|
|
|
clisession->bev = bufferevent_socket_new(adminserver.event_base, fd, TURN_BUFFEREVENTS_OPTIONS);
|
|
bufferevent_setcb(clisession->bev, cli_socket_input_handler_bev, NULL, cli_eventcb_bev, clisession);
|
|
bufferevent_setwatermark(clisession->bev, EV_READ | EV_WRITE, 0, BUFFEREVENT_HIGH_WATERMARK);
|
|
bufferevent_enable(clisession->bev, EV_READ); /* Start reading. */
|
|
|
|
clisession->ts = telnet_init(cli_telopts, cli_telnet_event_handler, 0, clisession);
|
|
|
|
if (!(clisession->ts)) {
|
|
const char *str = "Cannot open telnet session\n";
|
|
addr_debug_print(adminserver.verbose, (ioa_addr *)sa, str);
|
|
close_cli_session(clisession);
|
|
} else {
|
|
print_str_array(clisession, CLI_GREETING_STR);
|
|
telnet_printf(clisession->ts, "\n");
|
|
telnet_printf(clisession->ts, "Type '?' for help\n");
|
|
if (cli_password[0]) {
|
|
const char *ipwd = "Enter password: ";
|
|
telnet_printf(clisession->ts, "%s\n", ipwd);
|
|
} else {
|
|
type_cli_cursor(clisession);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void web_admin_input_handler(ioa_socket_handle s, int event_type, ioa_net_data *in_buffer, void *arg,
|
|
int can_resume) {
|
|
UNUSED_ARG(event_type);
|
|
UNUSED_ARG(can_resume);
|
|
UNUSED_ARG(arg);
|
|
|
|
int to_be_closed = 0;
|
|
|
|
int buffer_size = (int)ioa_network_buffer_get_size(in_buffer->nbh);
|
|
if (buffer_size >= UDP_STUN_BUFFER_SIZE) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "%s: request is too big: %d\n", __FUNCTION__, buffer_size);
|
|
to_be_closed = 1;
|
|
} else if (buffer_size > 0) {
|
|
|
|
SOCKET_TYPE st = get_ioa_socket_type(s);
|
|
|
|
if (is_stream_socket(st)) {
|
|
if (is_http((char *)ioa_network_buffer_data(in_buffer->nbh), buffer_size)) {
|
|
const char *proto = "HTTP";
|
|
ioa_network_buffer_data(in_buffer->nbh)[buffer_size] = 0;
|
|
if (st == TLS_SOCKET) {
|
|
proto = "HTTPS";
|
|
set_ioa_socket_app_type(s, HTTPS_CLIENT_SOCKET);
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s (%s %s) request: %s\n", __FUNCTION__, proto,
|
|
get_ioa_socket_cipher(s), get_ioa_socket_ssl_method(s),
|
|
(char *)ioa_network_buffer_data(in_buffer->nbh));
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s socket to be detached: 0x%lx, st=%d, sat=%d\n", __FUNCTION__, (long)s,
|
|
get_ioa_socket_type(s), get_ioa_socket_app_type(s));
|
|
|
|
ioa_socket_handle new_s = detach_ioa_socket(s);
|
|
if (new_s) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s new detached socket: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,
|
|
(long)new_s, get_ioa_socket_type(new_s), get_ioa_socket_app_type(new_s));
|
|
|
|
send_https_socket(new_s);
|
|
}
|
|
to_be_closed = 1;
|
|
|
|
} else {
|
|
set_ioa_socket_app_type(s, HTTP_CLIENT_SOCKET);
|
|
if (adminserver.verbose) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s request: %s\n", __FUNCTION__, proto,
|
|
(char *)ioa_network_buffer_data(in_buffer->nbh));
|
|
}
|
|
handle_http_echo(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (to_be_closed) {
|
|
if (adminserver.verbose) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: web-admin socket to be closed in client handler: s=0x%lx\n", __FUNCTION__,
|
|
(long)s);
|
|
}
|
|
set_ioa_socket_tobeclosed(s);
|
|
}
|
|
}
|
|
|
|
static int send_socket_to_admin_server(ioa_engine_handle e, struct message_to_relay *sm) {
|
|
// sm->relay_server is null for us.
|
|
|
|
sm->t = RMT_SOCKET;
|
|
|
|
if (sm->m.sm.s->defer_nbh) {
|
|
if (!sm->m.sm.nd.nbh) {
|
|
sm->m.sm.nd.nbh = sm->m.sm.s->defer_nbh;
|
|
sm->m.sm.s->defer_nbh = NULL;
|
|
} else {
|
|
ioa_network_buffer_delete(e, sm->m.sm.s->defer_nbh);
|
|
sm->m.sm.s->defer_nbh = NULL;
|
|
}
|
|
}
|
|
|
|
ioa_socket_handle s = sm->m.sm.s;
|
|
|
|
if (!s) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: web-admin socket EMPTY\n", __FUNCTION__);
|
|
|
|
} else if (s->read_event || s->bev) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: web-admin socket wrongly preset: 0x%lx : 0x%lx\n", __FUNCTION__,
|
|
(long)s->read_event, (long)s->bev);
|
|
|
|
IOA_CLOSE_SOCKET(s);
|
|
sm->m.sm.s = NULL;
|
|
} else {
|
|
s->e = e;
|
|
|
|
struct socket_message *msg = &(sm->m.sm);
|
|
|
|
if (register_callback_on_ioa_socket(e, msg->s, IOA_EV_READ, web_admin_input_handler, NULL, 0) < 0) {
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: Failed to register callback on web-admin ioa socket\n", __FUNCTION__);
|
|
IOA_CLOSE_SOCKET(s);
|
|
sm->m.sm.s = NULL;
|
|
|
|
} else {
|
|
|
|
if (msg->nd.nbh) {
|
|
web_admin_input_handler(msg->s, IOA_EV_READ, &(msg->nd), NULL, msg->can_resume);
|
|
ioa_network_buffer_delete(e, msg->nd.nbh);
|
|
msg->nd.nbh = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ioa_network_buffer_delete(e, sm->m.sm.nd.nbh);
|
|
sm->m.sm.nd.nbh = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void setup_admin_thread(void) {
|
|
adminserver.event_base = turn_event_base_new();
|
|
super_memory_t *sm = new_super_memory_region();
|
|
adminserver.e = create_ioa_engine(sm, adminserver.event_base, turn_params.listener.tp, turn_params.relay_ifname,
|
|
turn_params.relays_number, turn_params.relay_addrs, turn_params.default_relays,
|
|
turn_params.verbose
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
,
|
|
&turn_params.redis_statsdb
|
|
#endif
|
|
);
|
|
|
|
if (use_web_admin) {
|
|
// Support encryption on this ioa engine
|
|
// because the web-admin needs HTTPS
|
|
set_ssl_ctx(adminserver.e, &turn_params);
|
|
}
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "IO method (admin thread): %s\n", event_base_get_method(adminserver.event_base));
|
|
|
|
{
|
|
struct bufferevent *pair[2];
|
|
|
|
bufferevent_pair_new(adminserver.event_base, TURN_BUFFEREVENTS_OPTIONS, pair);
|
|
|
|
adminserver.in_buf = pair[0];
|
|
adminserver.out_buf = pair[1];
|
|
|
|
bufferevent_setcb(adminserver.in_buf, admin_server_receive_message, NULL, NULL, &adminserver);
|
|
bufferevent_enable(adminserver.in_buf, EV_READ);
|
|
}
|
|
|
|
{
|
|
struct bufferevent *pair[2];
|
|
|
|
bufferevent_pair_new(adminserver.event_base, TURN_BUFFEREVENTS_OPTIONS, pair);
|
|
|
|
adminserver.https_in_buf = pair[0];
|
|
adminserver.https_out_buf = pair[1];
|
|
|
|
bufferevent_setcb(adminserver.https_in_buf, https_admin_server_receive_message, NULL, NULL, &adminserver);
|
|
bufferevent_enable(adminserver.https_in_buf, EV_READ);
|
|
}
|
|
|
|
// Setup the web-admin server
|
|
if (use_web_admin) {
|
|
if (!web_admin_addr_set) {
|
|
if (make_ioa_addr((const uint8_t *)WEB_ADMIN_DEFAULT_IP, 0, &web_admin_addr) < 0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot set web-admin address %s\n", WEB_ADMIN_DEFAULT_IP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
addr_set_port(&web_admin_addr, web_admin_port);
|
|
|
|
char saddr[129];
|
|
addr_to_string_no_port(&web_admin_addr, (uint8_t *)saddr);
|
|
|
|
tls_listener_relay_server_type *tls_service =
|
|
create_tls_listener_server(turn_params.listener_ifname, saddr, web_admin_port, turn_params.verbose,
|
|
adminserver.e, send_socket_to_admin_server, NULL);
|
|
|
|
if (tls_service == NULL) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot create web-admin listener\n");
|
|
return;
|
|
}
|
|
|
|
addr_debug_print(adminserver.verbose, &web_admin_addr, "web-admin listener opened on ");
|
|
}
|
|
|
|
if (use_cli) {
|
|
if (!cli_addr_set) {
|
|
if (make_ioa_addr((const uint8_t *)CLI_DEFAULT_IP, 0, &cli_addr) < 0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot set cli address %s\n", CLI_DEFAULT_IP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
addr_set_port(&cli_addr, cli_port);
|
|
|
|
adminserver.listen_fd = socket(cli_addr.ss.sa_family, ADMIN_STREAM_SOCKET_TYPE, ADMIN_STREAM_SOCKET_PROTOCOL);
|
|
if (adminserver.listen_fd < 0) {
|
|
perror("socket");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open CLI socket\n");
|
|
return;
|
|
}
|
|
|
|
if (addr_bind(adminserver.listen_fd, &cli_addr, 1, 1, TCP_SOCKET) < 0) {
|
|
perror("Cannot bind CLI socket to addr");
|
|
char saddr[129];
|
|
addr_to_string(&cli_addr, (uint8_t *)saddr);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot bind CLI listener socket to addr %s\n", saddr);
|
|
socket_closesocket(adminserver.listen_fd);
|
|
return;
|
|
}
|
|
|
|
socket_tcp_set_keepalive(adminserver.listen_fd, TCP_SOCKET);
|
|
|
|
socket_set_nonblocking(adminserver.listen_fd);
|
|
|
|
adminserver.l = evconnlistener_new(adminserver.event_base, cliserver_input_handler, &adminserver,
|
|
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024, adminserver.listen_fd);
|
|
|
|
if (!(adminserver.l)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot create CLI listener\n");
|
|
socket_closesocket(adminserver.listen_fd);
|
|
return;
|
|
}
|
|
|
|
addr_debug_print(adminserver.verbose, &cli_addr, "CLI listener opened on ");
|
|
}
|
|
|
|
adminserver.sessions = ur_map_create();
|
|
}
|
|
|
|
void admin_server_receive_message(struct bufferevent *bev, void *ptr) {
|
|
UNUSED_ARG(ptr);
|
|
|
|
struct turn_session_info *tsi = (struct turn_session_info *)malloc(sizeof(struct turn_session_info));
|
|
turn_session_info_init(tsi);
|
|
int n = 0;
|
|
struct evbuffer *input = bufferevent_get_input(bev);
|
|
|
|
while ((n = evbuffer_remove(input, tsi, sizeof(struct turn_session_info))) > 0) {
|
|
if (n != sizeof(struct turn_session_info)) {
|
|
fprintf(stderr, "%s: Weird CLI buffer error: size=%d\n", __FUNCTION__, n);
|
|
continue;
|
|
}
|
|
|
|
ur_map_value_type t = 0;
|
|
if (ur_map_get(adminserver.sessions, (ur_map_key_type)tsi->id, &t) && t) {
|
|
struct turn_session_info *old = (struct turn_session_info *)t;
|
|
turn_session_info_clean(old);
|
|
free(old);
|
|
ur_map_del(adminserver.sessions, (ur_map_key_type)tsi->id, NULL);
|
|
}
|
|
|
|
if (tsi->valid) {
|
|
ur_map_put(adminserver.sessions, (ur_map_key_type)tsi->id, (ur_map_value_type)tsi);
|
|
tsi = (struct turn_session_info *)malloc(sizeof(struct turn_session_info));
|
|
turn_session_info_init(tsi);
|
|
} else {
|
|
turn_session_info_clean(tsi);
|
|
}
|
|
}
|
|
|
|
if (tsi) {
|
|
turn_session_info_clean(tsi);
|
|
free(tsi);
|
|
}
|
|
}
|
|
|
|
int send_turn_session_info(struct turn_session_info *tsi) {
|
|
int ret = -1;
|
|
|
|
if (tsi) {
|
|
struct evbuffer *output = bufferevent_get_output(adminserver.out_buf);
|
|
if (output) {
|
|
if (evbuffer_add(output, tsi, sizeof(struct turn_session_info)) >= 0) {
|
|
ret = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/////////// HTTPS /////////////
|
|
|
|
enum _AS_FORM {
|
|
AS_FORM_LOGON,
|
|
AS_FORM_LOGOUT,
|
|
AS_FORM_PC,
|
|
AS_FORM_HOME,
|
|
AS_FORM_TOGGLE,
|
|
AS_FORM_UPDATE,
|
|
AS_FORM_PS,
|
|
AS_FORM_USERS,
|
|
AS_FORM_SS,
|
|
AS_FORM_OS,
|
|
AS_FORM_OAUTH,
|
|
AS_FORM_OAUTH_SHOW_KEYS,
|
|
AS_FORM_UNKNOWN
|
|
};
|
|
|
|
typedef enum _AS_FORM AS_FORM;
|
|
|
|
#define HR_USERNAME "uname"
|
|
#define HR_PASSWORD "pwd"
|
|
#define HR_PASSWORD1 "pwd1"
|
|
#define HR_REALM "realm"
|
|
#define HR_ADD_USER "add_user"
|
|
#define HR_ADD_REALM "add_user_realm"
|
|
#define HR_ADD_SECRET "add_secret"
|
|
#define HR_ADD_ORIGIN "add_origin"
|
|
#define HR_CLIENT_PROTOCOL "cprotocol"
|
|
#define HR_USER_PATTERN "puser"
|
|
#define HR_MAX_SESSIONS "maxsess"
|
|
#define HR_CANCEL_SESSION "cs"
|
|
#define HR_DELETE_USER "du"
|
|
#define HR_DELETE_REALM "dr"
|
|
#define HR_DELETE_SECRET "ds"
|
|
#define HR_DELETE_ORIGIN "do"
|
|
#define HR_DELETE_IP "dip"
|
|
#define HR_DELETE_IP_REALM "dipr"
|
|
#define HR_DELETE_IP_KIND "dipk"
|
|
#define HR_ADD_IP "aip"
|
|
#define HR_ADD_IP_REALM "aipr"
|
|
#define HR_ADD_IP_KIND "aipk"
|
|
#define HR_UPDATE_PARAMETER "togglepar"
|
|
#define HR_ADD_OAUTH_KID "oauth_kid"
|
|
#define HR_ADD_OAUTH_REALM "oauth_realm"
|
|
#define HR_ADD_OAUTH_TS "oauth_ts"
|
|
#define HR_ADD_OAUTH_LT "oauth_lt"
|
|
#define HR_ADD_OAUTH_IKM "oauth_ikm"
|
|
#define HR_ADD_OAUTH_TEA "oauth_tea"
|
|
#define HR_DELETE_OAUTH_KID "oauth_kid_del"
|
|
#define HR_OAUTH_KID "kid"
|
|
|
|
struct form_name {
|
|
AS_FORM form;
|
|
const char *name;
|
|
};
|
|
|
|
static struct form_name form_names[] = {
|
|
{AS_FORM_LOGON, "/logon"}, {AS_FORM_LOGOUT, "/logout"}, {AS_FORM_PC, "/pc"},
|
|
{AS_FORM_HOME, "/home"}, {AS_FORM_TOGGLE, "/toggle"}, {AS_FORM_UPDATE, "/update"},
|
|
{AS_FORM_PS, "/ps"}, {AS_FORM_USERS, "/us"}, {AS_FORM_SS, "/ss"},
|
|
{AS_FORM_OS, "/os"}, {AS_FORM_OAUTH, "/oauth"}, {AS_FORM_OAUTH_SHOW_KEYS, "/oauth_show_keys"},
|
|
{AS_FORM_UNKNOWN, NULL}};
|
|
|
|
#define admin_title "TURN Server (https admin connection)"
|
|
#define __bold_admin_title "<b>TURN Server</b><br><i>https admin connection</i><br>\r\n"
|
|
#define bold_admin_title get_bold_admin_title()
|
|
|
|
static ioa_socket_handle current_socket = NULL;
|
|
|
|
static char *get_bold_admin_title(void) {
|
|
static char sbat[1025];
|
|
strncpy(sbat, __bold_admin_title, sizeof(sbat));
|
|
|
|
if (current_socket && current_socket->special_session) {
|
|
struct admin_session *as = (struct admin_session *)current_socket->special_session;
|
|
if (as->as_ok) {
|
|
if (as->as_login[0]) {
|
|
char *dst = sbat + strlen(sbat);
|
|
snprintf(dst, ADMIN_USER_MAX_LENGTH * 2 + 2, " admin user: <b><i>%s</i></b><br>\r\n", as->as_login);
|
|
}
|
|
if (as->as_realm[0]) {
|
|
char *dst = sbat + strlen(sbat);
|
|
snprintf(dst, STUN_MAX_REALM_SIZE * 2, " admin session realm: <b><i>%s</i></b><br>\r\n", as->as_realm);
|
|
} else if (as->as_eff_realm[0]) {
|
|
char *dst = sbat + strlen(sbat);
|
|
snprintf(dst, STUN_MAX_REALM_SIZE * 2, " admin session realm: <b><i>%s</i></b><br>\r\n", as->as_eff_realm);
|
|
}
|
|
}
|
|
}
|
|
return sbat;
|
|
}
|
|
|
|
static int wrong_html_name(const char *s) {
|
|
int ret = 0;
|
|
if (s) {
|
|
char *v = evhttp_encode_uri(s);
|
|
ret = strcmp(v, s);
|
|
free(v);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int is_as_ok(ioa_socket_handle s) {
|
|
return (s && s->special_session && ((struct admin_session *)s->special_session)->as_ok);
|
|
}
|
|
|
|
static int is_superuser(void) {
|
|
return (is_as_ok(current_socket) && (!((struct admin_session *)current_socket->special_session)->as_realm[0]));
|
|
}
|
|
|
|
static char *current_realm(void) {
|
|
if (current_socket && current_socket->special_session &&
|
|
((struct admin_session *)current_socket->special_session)->as_ok) {
|
|
return ((struct admin_session *)current_socket->special_session)->as_realm;
|
|
} else {
|
|
static char bad_realm[1025] = "_ERROR:UNKNOWN_REALM__";
|
|
return bad_realm;
|
|
}
|
|
}
|
|
|
|
static char *current_eff_realm(void) {
|
|
char *r = current_realm();
|
|
if (r && r[0])
|
|
return r;
|
|
else if (current_socket && current_socket->special_session &&
|
|
((struct admin_session *)current_socket->special_session)->as_ok) {
|
|
return ((struct admin_session *)current_socket->special_session)->as_eff_realm;
|
|
} else {
|
|
static char bad_eff_realm[1025] = "_ERROR:UNKNOWN_REALM__";
|
|
return bad_eff_realm;
|
|
}
|
|
}
|
|
|
|
static size_t current_max_output_sessions(void) {
|
|
if (current_socket && current_socket->special_session &&
|
|
((struct admin_session *)current_socket->special_session)->as_ok) {
|
|
return ((struct admin_session *)current_socket->special_session)->number_of_user_sessions;
|
|
}
|
|
return DEFAULT_CLI_MAX_OUTPUT_SESSIONS;
|
|
}
|
|
|
|
static void set_current_max_output_sessions(size_t value) {
|
|
if (current_socket && current_socket->special_session &&
|
|
((struct admin_session *)current_socket->special_session)->as_ok) {
|
|
((struct admin_session *)current_socket->special_session)->number_of_user_sessions = value;
|
|
}
|
|
}
|
|
|
|
static void https_cancel_session(const char *ssid) {
|
|
if (ssid && *ssid) {
|
|
turnsession_id sid = (turnsession_id)strtoull(ssid, NULL, 10);
|
|
send_session_cancellation_to_relay(sid);
|
|
}
|
|
}
|
|
|
|
static void https_print_top_page_header(struct str_buffer *sb) {
|
|
str_buffer_append(sb, "<!DOCTYPE html>\r\n<html>\r\n <head>\r\n <title>");
|
|
str_buffer_append(sb, admin_title);
|
|
str_buffer_append(
|
|
sb, "</title>\r\n <style> table, th, td { border: 1px solid black; border-collapse: collapse; text-align: left; "
|
|
"padding: 5px;} table#msg th { color: red; background-color: white; } </style> </head>\r\n <body>\r\n ");
|
|
str_buffer_append(sb, bold_admin_title);
|
|
}
|
|
|
|
static void https_print_page_header(struct str_buffer *sb) {
|
|
https_print_top_page_header(sb);
|
|
str_buffer_append(sb, "<br><a href=\"/home?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">home page</a><br>\r\n<br><a href=\"/logout\">logout</a><br>\r\n");
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
}
|
|
|
|
static void https_finish_page(struct str_buffer *sb, ioa_socket_handle s, int cclose) {
|
|
str_buffer_append(sb, "</body>\r\n</html>\r\n");
|
|
|
|
send_str_from_ioa_socket_tcp(s, "HTTP/1.1 200 OK\r\nServer: ");
|
|
if (!turn_params.no_software_attribute) {
|
|
send_str_from_ioa_socket_tcp(s, TURN_SOFTWARE);
|
|
}
|
|
send_str_from_ioa_socket_tcp(s, "\r\n");
|
|
send_str_from_ioa_socket_tcp(s, get_http_date_header());
|
|
if (cclose) {
|
|
send_str_from_ioa_socket_tcp(s, "Connection: close\r\n");
|
|
}
|
|
send_str_from_ioa_socket_tcp(s, "Content-Type: text/html; charset=UTF-8\r\nContent-Length: ");
|
|
|
|
send_ulong_from_ioa_socket_tcp(s, str_buffer_get_str_len(sb));
|
|
|
|
send_str_from_ioa_socket_tcp(s, "\r\n\r\n");
|
|
send_str_from_ioa_socket_tcp(s, str_buffer_get_str(sb));
|
|
|
|
str_buffer_free(sb);
|
|
}
|
|
|
|
static AS_FORM get_form(const char *path) {
|
|
if (path) {
|
|
size_t i = 0;
|
|
while (form_names[i].name) {
|
|
if (!strcmp(form_names[i].name, path))
|
|
return form_names[i].form;
|
|
++i;
|
|
}
|
|
}
|
|
return AS_FORM_UNKNOWN;
|
|
}
|
|
|
|
static void write_https_logon_page(ioa_socket_handle s) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_top_page_header(sb);
|
|
|
|
int we_have_admin_users = 0;
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->list_admin_users) {
|
|
int ausers = dbd->list_admin_users(1);
|
|
if (ausers > 0) {
|
|
we_have_admin_users = 1;
|
|
}
|
|
}
|
|
|
|
if (!we_have_admin_users) {
|
|
str_buffer_append(sb, "<br>To use the HTTPS admin connection, you have to set the database table "
|
|
"<b><i>admin_user</i></b> with the admin user accounts.<br>\r\n");
|
|
} else {
|
|
str_buffer_append(sb, "<br><br>\r\n");
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_LOGON].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(
|
|
sb,
|
|
" <fieldset><legend>Admin user information:</legend> user name:<br><input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_USERNAME);
|
|
str_buffer_append(sb, "\" value=\"\"><br>password:<br><input required type=\"password\" name=\"");
|
|
str_buffer_append(sb, HR_PASSWORD);
|
|
str_buffer_append(sb, "\" value=\"\"><br><br><input type=\"submit\" value=\"Login\"></fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
}
|
|
|
|
https_finish_page(sb, s, !we_have_admin_users);
|
|
}
|
|
}
|
|
|
|
static void write_https_home_page(ioa_socket_handle s) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_HOME].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Actions:</legend>\r\n");
|
|
|
|
str_buffer_append(sb, " Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled >");
|
|
} else {
|
|
str_buffer_append(sb, "> <input type=\"submit\" value=\"Set Admin Session Realm\" >");
|
|
}
|
|
|
|
str_buffer_append(sb, "<br>");
|
|
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_PC].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">Configuration Parameters</a>");
|
|
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_PS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "&");
|
|
str_buffer_append(sb, HR_MAX_SESSIONS);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append_sz(sb, current_max_output_sessions());
|
|
str_buffer_append(sb, "\">TURN Sessions</a>");
|
|
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_USERS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">Users</a>");
|
|
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_SS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">Shared Secrets (for TURN REST API)</a>");
|
|
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">Origins</a>");
|
|
|
|
if (is_superuser()) {
|
|
if (ENC_ALG_NUM > 0) {
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OAUTH].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\">oAuth keys</a>");
|
|
}
|
|
}
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sbprintf(struct str_buffer *sb, const char *format, ...) {
|
|
if (sb && format) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
char s[1025] = "\0";
|
|
vsnprintf(s, sizeof(s) - 1, format, args);
|
|
str_buffer_append(sb, s);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
static void https_print_flag(struct str_buffer *sb, int flag, const char *name, const char *param_name) {
|
|
if (sb && name) {
|
|
if (!is_superuser())
|
|
param_name = 0;
|
|
if (!param_name) {
|
|
sbprintf(sb, "<tr><td>%s</td><td>%s</td></tr>\r\n", name, get_flag(flag));
|
|
} else {
|
|
sbprintf(sb, "<tr><td>%s</td><td><a href=\"/toggle?%s=%s\">%s</a></td></tr>\r\n", name, HR_UPDATE_PARAMETER,
|
|
param_name, get_flag(flag));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void https_print_uint(struct str_buffer *sb, unsigned long value, const char *name, const char *param_name) {
|
|
if (sb && name) {
|
|
if (!is_superuser())
|
|
param_name = 0;
|
|
if (!param_name) {
|
|
if (value) {
|
|
sbprintf(sb, "<tr><td>%s</td><td>%lu</td></tr>\r\n", name, value);
|
|
} else {
|
|
sbprintf(sb, "<tr><td>%s</td><td> </td></tr>\r\n", name);
|
|
}
|
|
} else {
|
|
if (value) {
|
|
sbprintf(sb,
|
|
"<tr><td>%s</td><td> <form action=\"%s?%s=%s\" method=\"POST\"><input type=\"text\" name=\"%s\" "
|
|
"value=\"%lu\"><input type=\"submit\" value=\"Update\"></form> </td></tr>\r\n",
|
|
name, form_names[AS_FORM_UPDATE].name, HR_UPDATE_PARAMETER, param_name, param_name, value);
|
|
} else {
|
|
sbprintf(sb,
|
|
"<tr><td>%s</td><td> <form action=\"%s?%s=%s\" method=\"POST\"><input type=\"text\" name=\"%s\" "
|
|
"value=\"\"><input type=\"submit\" value=\"Update\"></form> </td></tr>\r\n",
|
|
name, form_names[AS_FORM_UPDATE].name, HR_UPDATE_PARAMETER, param_name, param_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void https_print_str(struct str_buffer *sb, const char *value, const char *name, const char *param_name) {
|
|
if (sb && name && value) {
|
|
if (!is_superuser())
|
|
param_name = 0;
|
|
if (!param_name) {
|
|
sbprintf(sb, "<tr><td>%s</td><td>%s</td></tr>\r\n", name, value);
|
|
} else {
|
|
sbprintf(sb,
|
|
"<tr><td>%s</td><td> <form action=\"%s?%s=%s\" method=\"POST\"><input type=\"text\" name=\"%s\" "
|
|
"value=\"%s\"><input type=\"submit\" value=\"Update\"></form> </td></tr>\r\n",
|
|
name, form_names[AS_FORM_UPDATE].name, HR_UPDATE_PARAMETER, param_name, param_name, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void https_print_str_array(struct str_buffer *sb, char **value, size_t sz, const char *name) {
|
|
if (sb && name && value && sz) {
|
|
size_t i;
|
|
for (i = 0; i < sz; i++) {
|
|
if (value[i]) {
|
|
sbprintf(sb, "<tr><td> %s</td><td> %s</td></tr>\r\n", name, value[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void https_print_addr(struct str_buffer *sb, ioa_addr *value, int use_port, const char *name) {
|
|
if (sb && name && value) {
|
|
char s[256];
|
|
if (!use_port)
|
|
addr_to_string_no_port(value, (uint8_t *)s);
|
|
else
|
|
addr_to_string(value, (uint8_t *)s);
|
|
sbprintf(sb, "<tr><td> %s</td><td> %s</td></tr>\r\n", name, s);
|
|
}
|
|
}
|
|
|
|
static size_t https_print_addr_list(struct str_buffer *sb, turn_server_addrs_list_t *value, int use_port,
|
|
const char *name) {
|
|
if (sb && name && value && value->size && value->addrs) {
|
|
char s[256];
|
|
size_t i;
|
|
for (i = 0; i < value->size; i++) {
|
|
if (!use_port)
|
|
addr_to_string_no_port(&(value->addrs[i]), (uint8_t *)s);
|
|
else
|
|
addr_to_string(&(value->addrs[i]), (uint8_t *)s);
|
|
sbprintf(sb, "</tr><td> %s</td><td> %s</td></tr>\r\n", name, s);
|
|
}
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const char *change_ip_addr_html(int dynamic, const char *kind, const char *ip, const char *realm, char *buffer,
|
|
size_t sz) {
|
|
if (!buffer || !sz) {
|
|
return "";
|
|
} else {
|
|
buffer[0] = 0;
|
|
if (dynamic && kind && ip) {
|
|
|
|
if (!realm)
|
|
realm = "";
|
|
|
|
if (current_realm()[0] && strcmp(current_realm(), realm)) {
|
|
// delete forbidden
|
|
} else {
|
|
char *eip = evhttp_encode_uri(ip);
|
|
snprintf(buffer, sz - 1, "<a href=\"%s?%s=%s&%s=%s&%s=%s\">delete</a>", form_names[AS_FORM_UPDATE].name,
|
|
HR_DELETE_IP_KIND, kind, HR_DELETE_IP_REALM, realm, HR_DELETE_IP, eip);
|
|
free(eip);
|
|
}
|
|
}
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
static void https_print_ip_range_list(struct str_buffer *sb, ip_range_list_t *value, const char *name, const char *kind,
|
|
int dynamic) {
|
|
if (sb && name) {
|
|
if (value && value->rs) {
|
|
size_t i;
|
|
char buffer[1025];
|
|
for (i = 0; i < value->ranges_number; ++i) {
|
|
if (value->rs[i].realm[0]) {
|
|
if (current_eff_realm()[0] && strcmp(current_eff_realm(), value->rs[i].realm)) {
|
|
continue;
|
|
} else {
|
|
sbprintf(sb, "<tr><td> %s</td><td> %s [%s] %s</td></tr>\r\n", name, value->rs[i].str, value->rs[i].realm,
|
|
change_ip_addr_html(dynamic, kind, value->rs[i].str, value->rs[i].realm, buffer, sizeof(buffer)));
|
|
}
|
|
} else {
|
|
sbprintf(sb, "<tr><td> %s</td><td> %s %s</td></tr>\r\n", name, value->rs[i].str,
|
|
change_ip_addr_html(dynamic, kind, value->rs[i].str, value->rs[i].realm, buffer, sizeof(buffer)));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dynamic) {
|
|
sbprintf(sb, "<tr><td> Add %s</td><td>", name);
|
|
sbprintf(
|
|
sb,
|
|
"<form action=\"%s?%s=%s\" method=\"POST\">IP range:<input required type=\"text\" name=\"%s\" value=\"\" >",
|
|
form_names[AS_FORM_UPDATE].name, HR_ADD_IP_KIND, kind, HR_ADD_IP);
|
|
sbprintf(sb, "Realm: <input type=\"text\" name=\"%s\" value=\"%s\" ", HR_ADD_IP_REALM, current_eff_realm());
|
|
if (!is_superuser()) {
|
|
sbprintf(sb, " disabled ");
|
|
}
|
|
sbprintf(sb, ">");
|
|
sbprintf(sb, "<input type=\"submit\" value=\"Add IP\"></form> </td></tr>\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void toggle_param(const char *pn) {
|
|
if (is_superuser()) {
|
|
if (pn) {
|
|
int i = 0;
|
|
while (tcmds[i].cmd && tcmds[i].data) {
|
|
if (strcmp(tcmds[i].cmd, pn) == 0) {
|
|
*(tcmds[i].data) = !(*(tcmds[i].data));
|
|
return;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void update_param(const char *pn, const char *value) {
|
|
if (pn) {
|
|
if (!value)
|
|
value = "0";
|
|
if (is_superuser()) {
|
|
if (strstr(pn, "total-quota") == pn) {
|
|
turn_params.total_quota = atoi(value);
|
|
} else if (strstr(pn, "user-quota") == pn) {
|
|
turn_params.user_quota = atoi(value);
|
|
} else if (strstr(pn, "max-bps") == pn) {
|
|
set_max_bps((band_limit_t)strtoul(value, NULL, 10));
|
|
} else if (strstr(pn, "bps-capacity") == pn) {
|
|
set_bps_capacity((band_limit_t)strtoul(value, NULL, 10));
|
|
}
|
|
}
|
|
{
|
|
realm_params_t *rp = get_realm(current_eff_realm());
|
|
if (!rp)
|
|
rp = get_realm(NULL);
|
|
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_realm_option_one) {
|
|
if (strstr(pn, "cr-total-quota") == pn) {
|
|
rp->options.perf_options.total_quota = atoi(value);
|
|
dbd->set_realm_option_one((uint8_t *)rp->options.name, rp->options.perf_options.total_quota, "total-quota");
|
|
} else if (strstr(pn, "cr-user-quota") == pn) {
|
|
rp->options.perf_options.user_quota = atoi(value);
|
|
dbd->set_realm_option_one((uint8_t *)rp->options.name, rp->options.perf_options.user_quota, "user-quota");
|
|
} else if (strstr(pn, "cr-max-bps") == pn) {
|
|
rp->options.perf_options.max_bps = (band_limit_t)strtoul(value, NULL, 10);
|
|
dbd->set_realm_option_one((uint8_t *)rp->options.name, rp->options.perf_options.max_bps, "max-bps");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void https_print_empty_row(struct str_buffer *sb, size_t span) {
|
|
str_buffer_append(sb, "<tr><td colspan=");
|
|
str_buffer_append_sz(sb, span);
|
|
str_buffer_append(sb, "><br></td></tr>");
|
|
}
|
|
|
|
static void write_pc_page(ioa_socket_handle s) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
str_buffer_append(sb, "<b>Configuration Parameters:</b><br><br><table style=\"width:100%\">\r\n");
|
|
str_buffer_append(sb, "<tr><th>Parameter</th><th>Value</th></tr>\r\n");
|
|
|
|
{
|
|
https_print_flag(sb, turn_params.verbose, "verbose", 0);
|
|
https_print_flag(sb, turn_params.turn_daemon, "daemon process", 0);
|
|
https_print_flag(sb, turn_params.stale_nonce, "stale-nonce", "stale-nonce");
|
|
https_print_flag(sb, turn_params.stun_only, "stun-only", "stun-only");
|
|
https_print_flag(sb, turn_params.no_stun, "no-stun", "no-stun");
|
|
https_print_flag(sb, turn_params.secure_stun, "secure-stun", "secure-stun");
|
|
https_print_flag(sb, turn_params.do_not_use_config_file, "do-not-use-config-file", 0);
|
|
https_print_flag(sb, turn_params.rfc5780, "RFC5780 support", 0);
|
|
https_print_uint(sb, (unsigned int)turn_params.net_engine_version, "net engine version", 0);
|
|
https_print_str(sb, turn_params.net_engine_version_txt[(int)turn_params.net_engine_version], "net engine", 0);
|
|
https_print_flag(sb, turn_params.fingerprint, "enforce fingerprints", 0);
|
|
https_print_flag(sb, turn_params.mobility, "mobility", "mobility");
|
|
https_print_flag(sb, turn_params.udp_self_balance, "udp-self-balance", 0);
|
|
https_print_str(sb, turn_params.pidfile, "pidfile", 0);
|
|
#if defined(WINDOWS)
|
|
// TODO: implement it!!!
|
|
#else
|
|
https_print_uint(sb, (unsigned long)getuid(), "process user ID", 0);
|
|
https_print_uint(sb, (unsigned long)getgid(), "process group ID", 0);
|
|
#endif
|
|
{
|
|
char wd[1025];
|
|
if (getcwd(wd, sizeof(wd) - 1)) {
|
|
https_print_str(sb, wd, "process dir", 0);
|
|
}
|
|
}
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
if (turn_params.cipher_list[0])
|
|
https_print_str(sb, turn_params.cipher_list, "cipher-list", 0);
|
|
else
|
|
https_print_str(sb, DEFAULT_CIPHER_LIST, "cipher-list", 0);
|
|
|
|
https_print_str(sb, turn_params.ec_curve_name, "ec-curve-name", 0);
|
|
{
|
|
if (turn_params.dh_key_size == DH_CUSTOM)
|
|
https_print_str(sb, turn_params.dh_file, "dh-file", 0);
|
|
else {
|
|
unsigned int dh_key_length = 1066;
|
|
if (turn_params.dh_key_size == DH_566)
|
|
dh_key_length = 566;
|
|
else if (turn_params.dh_key_size == DH_2066)
|
|
dh_key_length = 2066;
|
|
https_print_uint(sb, (unsigned long)dh_key_length, "DH-key-length", 0);
|
|
}
|
|
}
|
|
|
|
https_print_str(sb, turn_params.ca_cert_file, "Certificate Authority file", 0);
|
|
https_print_str(sb, turn_params.cert_file, "Certificate file", 0);
|
|
https_print_str(sb, turn_params.pkey_file, "Private Key file", 0);
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
https_print_str_array(sb, turn_params.listener.addrs, turn_params.listener.addrs_number, "Listener addr");
|
|
|
|
if (turn_params.listener_ifname[0])
|
|
https_print_str(sb, turn_params.listener_ifname, "listener-ifname", 0);
|
|
|
|
https_print_flag(sb, turn_params.no_udp, "no-udp", 0);
|
|
https_print_flag(sb, turn_params.no_tcp, "no-tcp", 0);
|
|
https_print_flag(sb, turn_params.no_dtls, "no-dtls", 0);
|
|
https_print_flag(sb, turn_params.no_tls, "no-tls", 0);
|
|
|
|
https_print_flag(sb, (!turn_params.no_tlsv1 && !turn_params.no_tls), "TLSv1.0", 0);
|
|
https_print_flag(sb, (!turn_params.no_tlsv1_1 && !turn_params.no_tls), "TLSv1.1", 0);
|
|
https_print_flag(sb, (!turn_params.no_tlsv1_2 && !turn_params.no_tls), "TLSv1.2", 0);
|
|
|
|
https_print_uint(sb, (unsigned long)turn_params.listener_port, "listener-port", 0);
|
|
https_print_uint(sb, (unsigned long)turn_params.tls_listener_port, "tls-listener-port", 0);
|
|
https_print_uint(sb, (unsigned long)turn_params.alt_listener_port, "alt-listener-port", 0);
|
|
https_print_uint(sb, (unsigned long)turn_params.alt_tls_listener_port, "alt-tls-listener-port", 0);
|
|
|
|
https_print_addr(sb, turn_params.external_ip, 0, "External public IP");
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
{
|
|
size_t an = https_print_addr_list(sb, &turn_params.aux_servers_list, 1, "Aux server");
|
|
an += https_print_addr_list(sb, &turn_params.alternate_servers_list, 1, "Alternate server");
|
|
an += https_print_addr_list(sb, &turn_params.tls_alternate_servers_list, 1, "TLS alternate server");
|
|
|
|
if (an) {
|
|
https_print_empty_row(sb, 2);
|
|
}
|
|
}
|
|
|
|
https_print_str_array(sb, turn_params.relay_addrs, turn_params.relays_number, "Relay addr");
|
|
|
|
if (turn_params.relay_ifname[0])
|
|
https_print_str(sb, turn_params.relay_ifname, "relay-ifname", 0);
|
|
|
|
https_print_flag(sb, turn_params.server_relay, "server-relay", 0);
|
|
|
|
https_print_flag(sb, turn_params.no_udp_relay, "no-udp-relay", "no-udp-relay");
|
|
https_print_flag(sb, turn_params.no_tcp_relay, "no-tcp-relay", "no-tcp-relay");
|
|
|
|
https_print_uint(sb, (unsigned long)turn_params.min_port, "min-port", 0);
|
|
https_print_uint(sb, (unsigned long)turn_params.max_port, "max-port", 0);
|
|
|
|
https_print_flag(sb, turn_params.no_multicast_peers, "no-multicast-peers", "no-multicast-peers");
|
|
https_print_flag(sb, turn_params.allow_loopback_peers, "allow-loopback-peers", "allow-loopback-peers");
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
if (turn_params.default_users_db.persistent_users_db.userdb[0]) {
|
|
switch (turn_params.default_users_db.userdb_type) {
|
|
#if !defined(TURN_NO_SQLITE)
|
|
case TURN_USERDB_TYPE_SQLITE:
|
|
https_print_str(sb, "SQLite", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
case TURN_USERDB_TYPE_PQ:
|
|
https_print_str(sb, "Postgres", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
case TURN_USERDB_TYPE_MYSQL:
|
|
https_print_str(sb, "MySQL/MariaDB", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
case TURN_USERDB_TYPE_MONGO:
|
|
https_print_str(sb, "MongoDB", "DB type", 0);
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
case TURN_USERDB_TYPE_REDIS:
|
|
https_print_str(sb, "redis", "DB type", 0);
|
|
break;
|
|
#endif
|
|
default:
|
|
https_print_str(sb, "unknown", "DB type", 0);
|
|
};
|
|
if (is_superuser()) {
|
|
https_print_str(sb, turn_params.default_users_db.persistent_users_db.userdb, "DB", 0);
|
|
}
|
|
} else {
|
|
https_print_str(sb, "none", "DB type", 0);
|
|
https_print_str(sb, "none", "DB", 0);
|
|
}
|
|
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
if (is_superuser()) {
|
|
if (turn_params.use_redis_statsdb && turn_params.redis_statsdb.connection_string_sanitized[0]) {
|
|
https_print_str(sb, turn_params.redis_statsdb.connection_string_sanitized, "Redis Statistics DB", 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
if (turn_params.ct == TURN_CREDENTIALS_LONG_TERM)
|
|
https_print_flag(sb, 1, "Long-term authorization mechanism", 0);
|
|
else
|
|
https_print_flag(sb, 1, "Anonymous credentials", 0);
|
|
https_print_flag(sb, turn_params.use_auth_secret_with_timestamp, "TURN REST API support", 0);
|
|
if (turn_params.use_auth_secret_with_timestamp) {
|
|
|
|
if (!turn_params.rest_api_separator || ((unsigned int)turn_params.rest_api_separator == (unsigned int)':')) {
|
|
https_print_str(sb, ":", "TURN REST API separator", 0);
|
|
} else {
|
|
https_print_uint(sb, turn_params.rest_api_separator, "TURN REST API separator ASCII number", 0);
|
|
}
|
|
}
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
if (is_superuser()) {
|
|
char *rn = get_realm(NULL)->options.name;
|
|
if (rn[0])
|
|
https_print_str(sb, rn, "Default realm", 0);
|
|
}
|
|
|
|
realm_params_t *rp = get_realm(current_eff_realm());
|
|
if (!rp)
|
|
rp = get_realm(NULL);
|
|
|
|
https_print_str(sb, rp->options.name, "Admin session (current) realm", 0);
|
|
|
|
https_print_uint(sb, (unsigned long)rp->options.perf_options.total_quota,
|
|
"current realm max number of sessions (total-quota)", "cr-total-quota");
|
|
https_print_uint(sb, (unsigned long)rp->options.perf_options.user_quota,
|
|
"current realm max sessions per user (user-quota)", "cr-user-quota");
|
|
https_print_uint(sb, (unsigned long)rp->options.perf_options.max_bps, "current realm max-bps (per session)",
|
|
"cr-max-bps");
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
https_print_uint(sb, (unsigned long)rp->status.total_current_allocs, "total-current-allocs", 0);
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
https_print_uint(sb, (unsigned long)turn_params.total_quota, "Default total-quota (per realm)", "total-quota");
|
|
https_print_uint(sb, (unsigned long)turn_params.user_quota, "Default user-quota (per realm)", "user-quota");
|
|
https_print_uint(sb, (unsigned long)get_bps_capacity(), "Total bps-capacity (per server)", "bps-capacity");
|
|
https_print_uint(sb, (unsigned long)get_bps_capacity_allocated(), "Allocated bps-capacity (per server)", 0);
|
|
https_print_uint(sb, (unsigned long)get_max_bps(), "Default max-bps (per session)", "max-bps");
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
https_print_ip_range_list(sb, &turn_params.ip_whitelist, "Whitelist IP (static)", NULL, 0);
|
|
{
|
|
ip_range_list_t *l = get_ip_list("allowed");
|
|
https_print_ip_range_list(sb, l, "Whitelist IP (dynamic)", "allowed", 1);
|
|
ip_list_free(l);
|
|
}
|
|
|
|
https_print_empty_row(sb, 2);
|
|
|
|
https_print_ip_range_list(sb, &turn_params.ip_blacklist, "Blacklist IP (static)", NULL, 0);
|
|
{
|
|
ip_range_list_t *l = get_ip_list("denied");
|
|
https_print_ip_range_list(sb, l, "Blacklist IP (dynamic)", "denied", 1);
|
|
ip_list_free(l);
|
|
}
|
|
}
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct https_ps_arg {
|
|
struct str_buffer *sb;
|
|
size_t counter;
|
|
turn_time_t ct;
|
|
const char *client_protocol;
|
|
const char *user_pattern;
|
|
size_t max_sessions;
|
|
turnsession_id cs;
|
|
};
|
|
|
|
static int https_print_session(ur_map_key_type key, ur_map_value_type value, void *arg) {
|
|
if (key && value && arg) {
|
|
struct https_ps_arg *csarg = (struct https_ps_arg *)arg;
|
|
struct str_buffer *sb = csarg->sb;
|
|
struct turn_session_info *tsi = (struct turn_session_info *)value;
|
|
|
|
if (current_eff_realm()[0] && strcmp(current_eff_realm(), tsi->realm))
|
|
return 0;
|
|
|
|
if (csarg->user_pattern[0]) {
|
|
if (!strstr((char *)tsi->username, csarg->user_pattern)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (csarg->cs == tsi->id) {
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
const char *pn = csarg->client_protocol;
|
|
if (pn[0]) {
|
|
if (!strcmp(pn, "TLS") || !strcmp(pn, "tls") || !strcmp(pn, "Tls")) {
|
|
if ((tsi->client_protocol != TLS_SOCKET) && (tsi->client_protocol != TLS_SCTP_SOCKET))
|
|
return 0;
|
|
} else if (!strcmp(pn, "DTLS") || !strcmp(pn, "dtls") || !strcmp(pn, "Dtls")) {
|
|
if (tsi->client_protocol != DTLS_SOCKET)
|
|
return 0;
|
|
} else if (!strcmp(pn, "TCP") || !strcmp(pn, "tcp") || !strcmp(pn, "Tcp")) {
|
|
if ((tsi->client_protocol != TCP_SOCKET) && (tsi->client_protocol != SCTP_SOCKET))
|
|
return 0;
|
|
} else if (!strcmp(pn, "UDP") || !strcmp(pn, "udp") || !strcmp(pn, "Udp")) {
|
|
if (tsi->client_protocol != UDP_SOCKET)
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((unsigned long)csarg->counter < (unsigned long)csarg->max_sessions) {
|
|
str_buffer_append(sb, "<tr><td>");
|
|
str_buffer_append_sz(sb, (size_t)(csarg->counter + 1));
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append_sid(sb, tsi->id);
|
|
str_buffer_append(sb, "<br><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_PS].name);
|
|
str_buffer_append(sb, "?cs=");
|
|
str_buffer_append_sid(sb, tsi->id);
|
|
str_buffer_append(sb, "\">cancel</a>");
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, (char *)tsi->username);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->realm);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->origin);
|
|
str_buffer_append(sb, "</td><td>");
|
|
if (turn_time_before(csarg->ct, tsi->start_time)) {
|
|
str_buffer_append(sb, "undefined time\n");
|
|
} else {
|
|
str_buffer_append_sz(sb, (size_t)(csarg->ct - tsi->start_time));
|
|
}
|
|
str_buffer_append(sb, "</td><td>");
|
|
if (turn_time_before(tsi->expiration_time, csarg->ct)) {
|
|
str_buffer_append(sb, "expired");
|
|
} else {
|
|
str_buffer_append_sz(sb, (size_t)(tsi->expiration_time - csarg->ct));
|
|
}
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, socket_type_name(tsi->client_protocol));
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, socket_type_name(tsi->peer_protocol));
|
|
str_buffer_append(sb, "</td><td>");
|
|
{
|
|
if (!tsi->local_addr_data.saddr[0])
|
|
addr_to_string(&(tsi->local_addr_data.addr), (uint8_t *)tsi->local_addr_data.saddr);
|
|
if (!tsi->remote_addr_data.saddr[0])
|
|
addr_to_string(&(tsi->remote_addr_data.addr), (uint8_t *)tsi->remote_addr_data.saddr);
|
|
if (!tsi->relay_addr_data_ipv4.saddr[0])
|
|
addr_to_string(&(tsi->relay_addr_data_ipv4.addr), (uint8_t *)tsi->relay_addr_data_ipv4.saddr);
|
|
if (!tsi->relay_addr_data_ipv6.saddr[0])
|
|
addr_to_string(&(tsi->relay_addr_data_ipv6.addr), (uint8_t *)tsi->relay_addr_data_ipv6.saddr);
|
|
str_buffer_append(sb, tsi->remote_addr_data.saddr);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->local_addr_data.saddr);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->relay_addr_data_ipv4.saddr);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->relay_addr_data_ipv6.saddr);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, get_flag(tsi->enforce_fingerprints));
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, get_flag(tsi->is_mobile));
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->tls_method);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append(sb, tsi->tls_cipher);
|
|
str_buffer_append(sb, "</td><td>");
|
|
str_buffer_append_sz(sb, (size_t)tsi->bps);
|
|
str_buffer_append(sb, "</td><td>");
|
|
{
|
|
char str[1025];
|
|
snprintf(str, sizeof(str) - 1, "rp=%lu, rb=%lu, sp=%lu, sb=%lu\n", (unsigned long)(tsi->received_packets),
|
|
(unsigned long)(tsi->received_bytes), (unsigned long)(tsi->sent_packets),
|
|
(unsigned long)(tsi->sent_bytes));
|
|
str_buffer_append(sb, str);
|
|
str_buffer_append(sb, "</td><td>");
|
|
}
|
|
{
|
|
char str[1025];
|
|
snprintf(str, sizeof(str) - 1, "r=%lu, s=%lu, total=%lu (bytes per sec)\n",
|
|
(unsigned long)(tsi->received_rate), (unsigned long)(tsi->sent_rate),
|
|
(unsigned long)(tsi->total_rate));
|
|
str_buffer_append(sb, str);
|
|
str_buffer_append(sb, "</td><td>");
|
|
}
|
|
|
|
if (tsi->main_peers_size) {
|
|
size_t i;
|
|
for (i = 0; i < tsi->main_peers_size; ++i) {
|
|
if (!(tsi->main_peers_data[i].saddr[0]))
|
|
addr_to_string(&(tsi->main_peers_data[i].addr), (uint8_t *)tsi->main_peers_data[i].saddr);
|
|
str_buffer_append(sb, " ");
|
|
str_buffer_append(sb, tsi->main_peers_data[i].saddr);
|
|
str_buffer_append(sb, " ");
|
|
}
|
|
if (tsi->extra_peers_size && tsi->extra_peers_data) {
|
|
for (i = 0; i < tsi->extra_peers_size; ++i) {
|
|
if (!(tsi->extra_peers_data[i].saddr[0]))
|
|
addr_to_string(&(tsi->extra_peers_data[i].addr), (uint8_t *)tsi->extra_peers_data[i].saddr);
|
|
str_buffer_append(sb, " ");
|
|
str_buffer_append(sb, tsi->extra_peers_data[i].saddr);
|
|
str_buffer_append(sb, " ");
|
|
}
|
|
}
|
|
}
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
}
|
|
|
|
csarg->counter += 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static size_t https_print_sessions(struct str_buffer *sb, const char *client_protocol, const char *user_pattern,
|
|
size_t max_sessions, turnsession_id cs) {
|
|
struct https_ps_arg arg = {sb, 0, 0, client_protocol, user_pattern, max_sessions, cs};
|
|
|
|
arg.ct = turn_time();
|
|
|
|
ur_map_foreach_arg(adminserver.sessions, (foreachcb_arg_type)https_print_session, &arg);
|
|
|
|
return arg.counter;
|
|
}
|
|
|
|
static void write_ps_page(ioa_socket_handle s, const char *client_protocol, const char *user_pattern,
|
|
size_t max_sessions, turnsession_id cs) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_PS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Filter:</legend>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, ">");
|
|
|
|
str_buffer_append(sb, " Client protocol: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_CLIENT_PROTOCOL);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, client_protocol);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, ">");
|
|
|
|
str_buffer_append(sb, " User name contains: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_USER_PATTERN);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, user_pattern);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br><br>");
|
|
|
|
str_buffer_append(sb, " Max number of output sessions in the page: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_MAX_SESSIONS);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append_sz(sb, max_sessions);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Filter\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><b>TURN Sessions:</b><br><br><table>\r\n");
|
|
str_buffer_append(
|
|
sb,
|
|
"<tr><th>N</th><th>Session ID</th><th>User</th><th>Realm</th><th>Origin</th><th>Age, secs</th><th>Expires, "
|
|
"secs</th><th>Client protocol</th><th>Relay protocol</th><th>Client addr</th><th>Server addr</th><th>Relay "
|
|
"addr (IPv4)</th><th>Relay addr (IPv6)</th><th>Fingerprints</th><th>Mobile</th><th>TLS method</th><th>TLS "
|
|
"cipher</th><th>BPS (allocated)</th><th>Packets</th><th>Rate</th><th>Peers</th></tr>\r\n");
|
|
|
|
size_t total_sz = https_print_sessions(sb, client_protocol, user_pattern, max_sessions, cs);
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br>Total sessions = ");
|
|
str_buffer_append_sz(sb, total_sz);
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static size_t https_print_users(struct str_buffer *sb) {
|
|
size_t ret = 0;
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->list_users) {
|
|
secrets_list_t users, realms;
|
|
init_secrets_list(&users);
|
|
init_secrets_list(&realms);
|
|
dbd->list_users((uint8_t *)current_eff_realm(), &users, &realms);
|
|
|
|
size_t sz = get_secrets_list_size(&users);
|
|
size_t i;
|
|
for (i = 0; i < sz; ++i) {
|
|
str_buffer_append(sb, "<tr><td>");
|
|
str_buffer_append_sz(sb, i + 1);
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&users, i));
|
|
str_buffer_append(sb, "</td>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
str_buffer_append(sb, "<td> <a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_USERS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_DELETE_USER);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&users, i));
|
|
str_buffer_append(sb, "&");
|
|
str_buffer_append(sb, HR_DELETE_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "\">delete</a>");
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "</tr>");
|
|
++ret;
|
|
}
|
|
|
|
clean_secrets_list(&users);
|
|
clean_secrets_list(&realms);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void write_users_page(ioa_socket_handle s, const uint8_t *add_user, const uint8_t *add_realm, const char *msg) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_USERS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Filter:</legend>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, ">");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Filter\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_USERS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>User:</legend>\r\n");
|
|
|
|
if (msg && msg[0]) {
|
|
str_buffer_append(sb, "<br><table id=\"msg\"><th>");
|
|
str_buffer_append(sb, msg);
|
|
str_buffer_append(sb, "</th></table><br>");
|
|
}
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_realm);
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>User name: <input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_USER);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_user);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Password: <input required type=\"password\" name=\"");
|
|
str_buffer_append(sb, HR_PASSWORD);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, "");
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Confirm password: <input required type=\"password\" name=\"");
|
|
str_buffer_append(sb, HR_PASSWORD1);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, "");
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br><br>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Add user\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><b>Users:</b><br><br>\r\n");
|
|
str_buffer_append(sb, "<table>\r\n");
|
|
str_buffer_append(sb, "<tr><th>N</th><th>Name</th>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<th>Realm</th>");
|
|
}
|
|
str_buffer_append(sb, "<th> </th>");
|
|
str_buffer_append(sb, "</tr>\r\n");
|
|
|
|
size_t total_sz = https_print_users(sb);
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br>Total users = ");
|
|
str_buffer_append_sz(sb, total_sz);
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static size_t https_print_secrets(struct str_buffer *sb) {
|
|
size_t ret = 0;
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->list_secrets) {
|
|
secrets_list_t secrets, realms;
|
|
init_secrets_list(&secrets);
|
|
init_secrets_list(&realms);
|
|
dbd->list_secrets((uint8_t *)current_eff_realm(), &secrets, &realms);
|
|
|
|
size_t sz = get_secrets_list_size(&secrets);
|
|
size_t i;
|
|
for (i = 0; i < sz; ++i) {
|
|
str_buffer_append(sb, "<tr><td>");
|
|
str_buffer_append_sz(sb, i + 1);
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&secrets, i));
|
|
str_buffer_append(sb, "</td>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
str_buffer_append(sb, "<td> <a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_SS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_DELETE_SECRET);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&secrets, i));
|
|
str_buffer_append(sb, "&");
|
|
str_buffer_append(sb, HR_DELETE_REALM);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "\">delete</a>");
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "</tr>");
|
|
++ret;
|
|
}
|
|
|
|
clean_secrets_list(&secrets);
|
|
clean_secrets_list(&realms);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void write_shared_secrets_page(ioa_socket_handle s, const char *add_secret, const char *add_realm,
|
|
const char *msg) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_SS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Filter:</legend>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, ">");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Filter\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_SS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Secret:</legend>\r\n");
|
|
|
|
if (msg && msg[0]) {
|
|
str_buffer_append(sb, "<br><table id=\"msg\"><th>");
|
|
str_buffer_append(sb, msg);
|
|
str_buffer_append(sb, "</th></table><br>");
|
|
}
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_realm);
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Secret: <input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_SECRET);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_secret);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Add secret\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><b>Shared secrets:</b><br><br>\r\n");
|
|
str_buffer_append(sb, "<table>\r\n");
|
|
str_buffer_append(sb, "<tr><th>N</th><th>Value</th>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<th>Realm</th>");
|
|
}
|
|
str_buffer_append(sb, "<th> </th>");
|
|
str_buffer_append(sb, "</tr>\r\n");
|
|
|
|
size_t total_sz = https_print_secrets(sb);
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br>Total secrets = ");
|
|
str_buffer_append_sz(sb, total_sz);
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static size_t https_print_origins(struct str_buffer *sb) {
|
|
size_t ret = 0;
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->list_origins) {
|
|
secrets_list_t origins, realms;
|
|
init_secrets_list(&origins);
|
|
init_secrets_list(&realms);
|
|
dbd->list_origins((uint8_t *)current_eff_realm(), &origins, &realms);
|
|
|
|
size_t sz = get_secrets_list_size(&origins);
|
|
size_t i;
|
|
for (i = 0; i < sz; ++i) {
|
|
str_buffer_append(sb, "<tr><td>");
|
|
str_buffer_append_sz(sb, i + 1);
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&origins, i));
|
|
str_buffer_append(sb, "</td>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
if (is_superuser()) {
|
|
str_buffer_append(sb, "<td> <a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_DELETE_ORIGIN);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&origins, i));
|
|
str_buffer_append(sb, "\">delete</a>");
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
str_buffer_append(sb, "</tr>");
|
|
++ret;
|
|
}
|
|
|
|
clean_secrets_list(&origins);
|
|
clean_secrets_list(&realms);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void write_origins_page(ioa_socket_handle s, const char *add_origin, const char *add_realm, const char *msg) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Filter:</legend>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, current_eff_realm());
|
|
str_buffer_append(sb, "\"");
|
|
if (!is_superuser()) {
|
|
str_buffer_append(sb, " disabled ");
|
|
}
|
|
str_buffer_append(sb, ">");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Filter\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
|
|
if (is_superuser()) {
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OS].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>Origin:</legend>\r\n");
|
|
|
|
if (msg && msg[0]) {
|
|
str_buffer_append(sb, "<br><table id=\"msg\"><th>");
|
|
str_buffer_append(sb, msg);
|
|
str_buffer_append(sb, "</th></table><br>");
|
|
}
|
|
|
|
str_buffer_append(sb, " <br>Realm name: <input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_realm);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, " <br>Origin: <input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_ORIGIN);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_origin);
|
|
str_buffer_append(sb, "\"");
|
|
str_buffer_append(sb, "><br>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Add origin\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "<br><b>Origins:</b><br><br>\r\n");
|
|
str_buffer_append(sb, "<table>\r\n");
|
|
str_buffer_append(sb, "<tr><th>N</th><th>Value</th>");
|
|
if (!current_eff_realm()[0]) {
|
|
str_buffer_append(sb, "<th>Realm</th>");
|
|
}
|
|
if (is_superuser()) {
|
|
str_buffer_append(sb, "<th> </th>");
|
|
}
|
|
str_buffer_append(sb, "</tr>\r\n");
|
|
|
|
size_t total_sz = https_print_origins(sb);
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br>Total origins = ");
|
|
str_buffer_append_sz(sb, total_sz);
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static size_t https_print_oauth_keys(struct str_buffer *sb) {
|
|
size_t ret = 0;
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->list_oauth_keys) {
|
|
secrets_list_t kids, teas, tss, lts, realms;
|
|
init_secrets_list(&kids);
|
|
init_secrets_list(&teas);
|
|
init_secrets_list(&tss);
|
|
init_secrets_list(<s);
|
|
init_secrets_list(&realms);
|
|
dbd->list_oauth_keys(&kids, &teas, &tss, <s, &realms);
|
|
|
|
size_t sz = get_secrets_list_size(&kids);
|
|
size_t i;
|
|
for (i = 0; i < sz; ++i) {
|
|
str_buffer_append(sb, "<tr><td>");
|
|
str_buffer_append_sz(sb, i + 1);
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&kids, i));
|
|
str_buffer_append(sb, "</td>");
|
|
|
|
str_buffer_append(sb, "<td><a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OAUTH_SHOW_KEYS].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_OAUTH_KID);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&kids, i));
|
|
str_buffer_append(sb, "\"> show </a></td>");
|
|
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&tss, i));
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(<s, i));
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&teas, i));
|
|
str_buffer_append(sb, "</td>");
|
|
str_buffer_append(sb, "<td>");
|
|
str_buffer_append(sb, get_secrets_list_elem(&realms, i));
|
|
str_buffer_append(sb, "</td>");
|
|
|
|
{
|
|
str_buffer_append(sb, "<td> <a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OAUTH].name);
|
|
str_buffer_append(sb, "?");
|
|
str_buffer_append(sb, HR_DELETE_OAUTH_KID);
|
|
str_buffer_append(sb, "=");
|
|
str_buffer_append(sb, get_secrets_list_elem(&kids, i));
|
|
str_buffer_append(sb, "\">delete</a>");
|
|
str_buffer_append(sb, "</td>");
|
|
}
|
|
str_buffer_append(sb, "</tr>");
|
|
++ret;
|
|
}
|
|
|
|
clean_secrets_list(&kids);
|
|
clean_secrets_list(&teas);
|
|
clean_secrets_list(&tss);
|
|
clean_secrets_list(<s);
|
|
clean_secrets_list(&realms);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void write_https_oauth_show_keys(ioa_socket_handle s, const char *kid) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else if (!is_superuser()) {
|
|
write_https_home_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
str_buffer_append(sb, "<a href=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OAUTH].name);
|
|
str_buffer_append(sb, "\">back to oauth list</a><br><br>\r\n");
|
|
|
|
if (kid && kid[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->get_oauth_key) {
|
|
oauth_key_data_raw key;
|
|
if ((*dbd->get_oauth_key)((const uint8_t *)kid, &key) < 0) {
|
|
str_buffer_append(sb, "data retrieval error");
|
|
} else {
|
|
|
|
oauth_key_data okd;
|
|
memset(&okd, 0, sizeof(okd));
|
|
|
|
convert_oauth_key_data_raw(&key, &okd);
|
|
|
|
char err_msg[1025] = "\0";
|
|
size_t err_msg_size = sizeof(err_msg) - 1;
|
|
|
|
oauth_key okey;
|
|
memset(&okey, 0, sizeof(okey));
|
|
|
|
if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) {
|
|
str_buffer_append(sb, err_msg);
|
|
} else {
|
|
|
|
str_buffer_append(sb, "<table>\r\n");
|
|
|
|
if (key.ikm_key[0]) {
|
|
str_buffer_append(sb, "<tr><td>Base64-encoded key:</td><td>");
|
|
str_buffer_append(sb, key.ikm_key);
|
|
str_buffer_append(sb, "</td></tr>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</table>\r\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void write_https_oauth_page(ioa_socket_handle s, const char *add_kid, const char *add_ikm, const char *add_tea,
|
|
const char *add_ts, const char *add_lt, const char *add_realm, const char *msg) {
|
|
if (s && !ioa_socket_tobeclosed(s)) {
|
|
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else if (!is_superuser()) {
|
|
write_https_home_page(s);
|
|
} else {
|
|
|
|
struct str_buffer *sb = str_buffer_new();
|
|
|
|
https_print_page_header(sb);
|
|
|
|
{
|
|
str_buffer_append(sb, "<form action=\"");
|
|
str_buffer_append(sb, form_names[AS_FORM_OAUTH].name);
|
|
str_buffer_append(sb, "\" method=\"POST\">\r\n");
|
|
str_buffer_append(sb, " <fieldset><legend>oAuth key:</legend>\r\n");
|
|
|
|
if (msg && msg[0]) {
|
|
str_buffer_append(sb, "<br><table id=\"msg\"><th>");
|
|
str_buffer_append(sb, msg);
|
|
str_buffer_append(sb, "</th></table><br>");
|
|
}
|
|
|
|
str_buffer_append(sb, "<table><tr><td>");
|
|
|
|
{
|
|
if (!add_kid)
|
|
add_kid = "";
|
|
|
|
str_buffer_append(sb, " <br>KID (required): <input required type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_KID);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_kid);
|
|
str_buffer_append(sb, "\"><br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td><td>");
|
|
|
|
{
|
|
if (!add_ts)
|
|
add_ts = "";
|
|
|
|
str_buffer_append(sb, " <br>Timestamp, secs (optional): <input type=\"number\" min=\"0\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_TS);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_ts);
|
|
str_buffer_append(sb, "\"><br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td><td>");
|
|
|
|
{
|
|
if (!add_lt)
|
|
add_lt = "";
|
|
|
|
str_buffer_append(sb, " <br>Lifetime, secs (optional): <input type=\"number\" min=\"0\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_LT);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_lt);
|
|
str_buffer_append(sb, "\"><br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td></tr>\r\n");
|
|
|
|
str_buffer_append(sb, "<tr><td colspan=\"1\">");
|
|
|
|
{
|
|
if (!add_ikm)
|
|
add_ikm = "";
|
|
|
|
str_buffer_append(sb, " <br>Base64-encoded input keying material (required):<br><textarea wrap=\"soft\" "
|
|
"cols=40 rows=4 name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_IKM);
|
|
str_buffer_append(sb, "\" maxLength=256 >");
|
|
str_buffer_append(sb, (const char *)add_ikm);
|
|
str_buffer_append(sb, "</textarea>");
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td><td>");
|
|
|
|
{
|
|
if (!add_realm)
|
|
add_realm = "";
|
|
|
|
str_buffer_append(sb, " <br>Realm (optional): <input type=\"text\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_REALM);
|
|
str_buffer_append(sb, "\" value=\"");
|
|
str_buffer_append(sb, (const char *)add_realm);
|
|
str_buffer_append(sb, "\"><br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td><td>");
|
|
|
|
{
|
|
str_buffer_append(sb, "<br>Token encryption algorithm (required):<br>\r\n");
|
|
|
|
if (!add_tea || !add_tea[0])
|
|
add_tea = "A256GCM";
|
|
|
|
str_buffer_append(sb, "<input type=\"radio\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_TEA);
|
|
str_buffer_append(sb, "\" value=\"A128GCM\" ");
|
|
if (!strcmp("A128GCM", add_tea)) {
|
|
str_buffer_append(sb, " checked ");
|
|
}
|
|
str_buffer_append(sb, ">A128GCM\r\n<br>\r\n");
|
|
|
|
str_buffer_append(sb, "<input type=\"radio\" name=\"");
|
|
str_buffer_append(sb, HR_ADD_OAUTH_TEA);
|
|
str_buffer_append(sb, "\" value=\"A256GCM\" ");
|
|
if (!strcmp("A256GCM", add_tea)) {
|
|
str_buffer_append(sb, " checked ");
|
|
}
|
|
str_buffer_append(sb, ">A256GCM\r\n<br>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "</td></tr>\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br><input type=\"submit\" value=\"Add key\">");
|
|
|
|
str_buffer_append(sb, "</fieldset>\r\n");
|
|
str_buffer_append(sb, "</form>\r\n");
|
|
}
|
|
|
|
str_buffer_append(sb, "<br><b>OAuth keys:</b><br><br>\r\n");
|
|
str_buffer_append(sb, "<table>\r\n");
|
|
str_buffer_append(sb, "<tr><th>N</th><th>KID</th><th>keys</th>");
|
|
str_buffer_append(sb, "<th>Timestamp, secs</th>");
|
|
str_buffer_append(sb, "<th>Lifetime,secs</th>");
|
|
str_buffer_append(sb, "<th>Token encryption algorithm</th>");
|
|
str_buffer_append(sb, "<th>Realm</th>");
|
|
str_buffer_append(sb, "<th> </th>");
|
|
str_buffer_append(sb, "</tr>\r\n");
|
|
|
|
size_t total_sz = https_print_oauth_keys(sb);
|
|
|
|
str_buffer_append(sb, "\r\n</table>\r\n");
|
|
|
|
str_buffer_append(sb, "<br>Total oAuth keys = ");
|
|
str_buffer_append_sz(sb, total_sz);
|
|
str_buffer_append(sb, "<br>\r\n");
|
|
|
|
https_finish_page(sb, s, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void handle_toggle_request(ioa_socket_handle s, struct http_request *hr) {
|
|
if (s && hr) {
|
|
const char *param = get_http_header_value(hr, HR_UPDATE_PARAMETER, NULL);
|
|
toggle_param(param);
|
|
}
|
|
}
|
|
|
|
static void handle_update_request(ioa_socket_handle s, struct http_request *hr) {
|
|
if (s && hr) {
|
|
{
|
|
const char *param = get_http_header_value(hr, HR_UPDATE_PARAMETER, NULL);
|
|
if (param) {
|
|
update_param(param, get_http_header_value(hr, param, ""));
|
|
}
|
|
}
|
|
|
|
{
|
|
const char *eip = get_http_header_value(hr, HR_DELETE_IP, NULL);
|
|
if (eip && eip[0]) {
|
|
char *ip = evhttp_decode_uri(eip);
|
|
const char *r = get_http_header_value(hr, HR_DELETE_IP_REALM, "");
|
|
const char *kind = get_http_header_value(hr, HR_DELETE_IP_KIND, "");
|
|
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_permission_ip) {
|
|
|
|
if (!r || !r[0]) {
|
|
r = current_realm();
|
|
}
|
|
|
|
if (current_realm()[0] && strcmp(current_realm(), r)) {
|
|
// forbidden
|
|
} else if (strcmp(kind, "allowed") != 0 && strcmp(kind, "denied") != 0) {
|
|
// forbidden
|
|
} else {
|
|
|
|
uint8_t realm[STUN_MAX_REALM_SIZE + 1] = "\0";
|
|
STRCPY(realm, r);
|
|
|
|
dbd->set_permission_ip(kind, realm, ip, 1);
|
|
}
|
|
}
|
|
free(ip);
|
|
}
|
|
}
|
|
|
|
{
|
|
const char *eip = get_http_header_value(hr, HR_ADD_IP, NULL);
|
|
if (eip && eip[0]) {
|
|
char *ip = evhttp_decode_uri(eip);
|
|
|
|
if (check_ip_list_range(ip) < 0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong address range format: %s\n", ip);
|
|
} else {
|
|
|
|
const char *r = get_http_header_value(hr, HR_ADD_IP_REALM, "");
|
|
const char *kind = get_http_header_value(hr, HR_ADD_IP_KIND, "");
|
|
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_permission_ip) {
|
|
|
|
if (!r || !r[0]) {
|
|
r = current_realm();
|
|
}
|
|
|
|
if (current_realm()[0] && strcmp(current_realm(), r)) {
|
|
// forbidden
|
|
} else if (strcmp(kind, "allowed") != 0 && strcmp(kind, "denied") != 0) {
|
|
// forbidden
|
|
} else {
|
|
|
|
uint8_t realm[STUN_MAX_REALM_SIZE + 1] = "\0";
|
|
STRCPY(realm, r);
|
|
|
|
dbd->set_permission_ip(kind, realm, ip, 0);
|
|
}
|
|
}
|
|
}
|
|
free(ip);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void handle_logon_request(ioa_socket_handle s, struct http_request *hr) {
|
|
if (s && hr) {
|
|
const char *uname = get_http_header_value(hr, HR_USERNAME, NULL);
|
|
const char *pwd = get_http_header_value(hr, HR_PASSWORD, NULL);
|
|
|
|
struct admin_session *as = (struct admin_session *)s->special_session;
|
|
if (!as) {
|
|
as = (struct admin_session *)calloc(sizeof(struct admin_session), 1);
|
|
s->special_session = as;
|
|
s->special_session_size = sizeof(struct admin_session);
|
|
}
|
|
|
|
if (!(as->as_ok) && uname && is_secure_string((const uint8_t *)uname, 1) && pwd) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->get_admin_user) {
|
|
password_t password;
|
|
char realm[STUN_MAX_REALM_SIZE + 1] = "\0";
|
|
if ((*(dbd->get_admin_user))((const uint8_t *)uname, (uint8_t *)realm, password) >= 0) {
|
|
if (!check_password(pwd, (char *)password)) {
|
|
STRCPY(as->as_login, uname);
|
|
STRCPY(as->as_realm, realm);
|
|
as->as_eff_realm[0] = 0;
|
|
as->as_ok = 1;
|
|
as->number_of_user_sessions = DEFAULT_CLI_MAX_OUTPUT_SESSIONS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void handle_logout_request(ioa_socket_handle s, struct http_request *hr) {
|
|
UNUSED_ARG(hr);
|
|
if (s) {
|
|
struct admin_session *as = (struct admin_session *)s->special_session;
|
|
if (as) {
|
|
as->as_login[0] = 0;
|
|
as->as_ok = 0;
|
|
as->as_realm[0] = 0;
|
|
as->as_eff_realm[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh) {
|
|
current_socket = s;
|
|
|
|
if (turn_params.verbose) {
|
|
if (nbh) {
|
|
((char *)ioa_network_buffer_data(nbh))[ioa_network_buffer_get_size(nbh)] = 0;
|
|
if (!strstr((char *)ioa_network_buffer_data(nbh), "pwd")) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: HTTPS connection input: %s\n", __FUNCTION__,
|
|
(char *)ioa_network_buffer_data(nbh));
|
|
}
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: HTTPS connection initial input\n", __FUNCTION__);
|
|
}
|
|
}
|
|
|
|
if (!nbh) {
|
|
write_https_logon_page(s);
|
|
} else {
|
|
((char *)ioa_network_buffer_data(nbh))[ioa_network_buffer_get_size(nbh)] = 0;
|
|
struct http_request *hr = parse_http_request((char *)ioa_network_buffer_data(nbh));
|
|
if (!hr) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: wrong HTTPS request (I cannot parse it)\n", __FUNCTION__);
|
|
write_https_logon_page(s);
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: HTTPS request, path %s\n", __FUNCTION__, hr->path);
|
|
|
|
AS_FORM form = get_form(hr->path);
|
|
|
|
switch (form) {
|
|
case AS_FORM_PC: {
|
|
if (is_as_ok(s)) {
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
write_pc_page(s);
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_PS: {
|
|
if (is_as_ok(s)) {
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
|
|
const char *client_protocol = get_http_header_value(hr, HR_CLIENT_PROTOCOL, "");
|
|
|
|
const char *user_pattern = get_http_header_value(hr, HR_USER_PATTERN, "");
|
|
|
|
turnsession_id csid = 0;
|
|
const char *ssid = get_http_header_value(hr, HR_CANCEL_SESSION, NULL);
|
|
if (ssid) {
|
|
https_cancel_session(ssid);
|
|
csid = (turnsession_id)strtoull(ssid, NULL, 10);
|
|
}
|
|
|
|
size_t max_sessions = current_max_output_sessions();
|
|
const char *s_max_sessions = get_http_header_value(hr, HR_MAX_SESSIONS, NULL);
|
|
if (s_max_sessions) {
|
|
max_sessions = strtoul(s_max_sessions, NULL, 10);
|
|
if (!max_sessions)
|
|
max_sessions = current_max_output_sessions();
|
|
set_current_max_output_sessions(max_sessions);
|
|
}
|
|
|
|
if (!max_sessions)
|
|
max_sessions = DEFAULT_CLI_MAX_OUTPUT_SESSIONS;
|
|
|
|
write_ps_page(s, client_protocol, user_pattern, max_sessions, csid);
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_USERS: {
|
|
if (is_as_ok(s)) {
|
|
{
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
}
|
|
|
|
{
|
|
const uint8_t *user = (const uint8_t *)get_http_header_value(hr, HR_DELETE_USER, NULL);
|
|
if (user && user[0]) {
|
|
const uint8_t *realm = (const uint8_t *)get_http_header_value(hr, HR_DELETE_REALM, "");
|
|
if (!is_superuser()) {
|
|
realm = (const uint8_t *)current_realm();
|
|
}
|
|
if (realm && realm[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->del_user) {
|
|
uint8_t u[STUN_MAX_USERNAME_SIZE + 1];
|
|
uint8_t r[STUN_MAX_REALM_SIZE + 1];
|
|
STRCPY(u, user);
|
|
STRCPY(r, realm);
|
|
dbd->del_user(u, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const uint8_t *add_realm = (const uint8_t *)current_eff_realm();
|
|
const uint8_t *add_user = (const uint8_t *)get_http_header_value(hr, HR_ADD_USER, "");
|
|
const char *msg = "";
|
|
if (wrong_html_name((const char *)add_user)) {
|
|
msg = "Error: wrong user name";
|
|
add_user = (const uint8_t *)"";
|
|
}
|
|
if (add_user[0]) {
|
|
add_realm = (const uint8_t *)get_http_header_value(hr, HR_ADD_REALM, current_realm());
|
|
if (!is_superuser()) {
|
|
add_realm = (const uint8_t *)current_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)current_eff_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)get_realm(NULL)->options.name;
|
|
}
|
|
if (wrong_html_name((const char *)add_realm)) {
|
|
msg = "Error: wrong realm name";
|
|
add_realm = (const uint8_t *)"";
|
|
}
|
|
if (add_realm[0]) {
|
|
const uint8_t *pwd = (const uint8_t *)get_http_header_value(hr, HR_PASSWORD, NULL);
|
|
const uint8_t *pwd1 = (const uint8_t *)get_http_header_value(hr, HR_PASSWORD1, NULL);
|
|
if (pwd && pwd1 && pwd[0] && pwd1[0] && !strcmp((const char *)pwd, (const char *)pwd1)) {
|
|
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_user_key) {
|
|
|
|
hmackey_t key;
|
|
char skey[sizeof(hmackey_t) * 2 + 1];
|
|
|
|
{
|
|
uint8_t u[STUN_MAX_USERNAME_SIZE + 1];
|
|
uint8_t r[STUN_MAX_REALM_SIZE + 1];
|
|
uint8_t p[STUN_MAX_PWD_SIZE + 1];
|
|
STRCPY(u, add_user);
|
|
STRCPY(r, add_realm);
|
|
STRCPY(p, pwd);
|
|
stun_produce_integrity_key_str(u, r, p, key, SHATYPE_DEFAULT);
|
|
size_t i = 0;
|
|
size_t sz = get_hmackey_size(SHATYPE_DEFAULT);
|
|
int maxsz = (int)(sz * 2) + 1;
|
|
char *s = skey;
|
|
for (i = 0; (i < sz) && (maxsz > 2); i++) {
|
|
snprintf(s, (size_t)(sz * 2), "%02x", (unsigned int)key[i]);
|
|
maxsz -= 2;
|
|
s += 2;
|
|
}
|
|
skey[sz * 2] = 0;
|
|
|
|
(*dbd->set_user_key)(u, r, skey);
|
|
}
|
|
|
|
add_realm = (const uint8_t *)"";
|
|
add_user = (const uint8_t *)"";
|
|
}
|
|
} else {
|
|
msg = "Error: wrong password";
|
|
}
|
|
}
|
|
}
|
|
|
|
write_users_page(s, add_user, add_realm, msg);
|
|
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_SS: {
|
|
if (is_as_ok(s)) {
|
|
{
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
}
|
|
|
|
{
|
|
const uint8_t *secret = (const uint8_t *)get_http_header_value(hr, HR_DELETE_SECRET, NULL);
|
|
if (secret && secret[0]) {
|
|
const uint8_t *realm = (const uint8_t *)get_http_header_value(hr, HR_DELETE_REALM, NULL);
|
|
if (!is_superuser()) {
|
|
realm = (const uint8_t *)current_realm();
|
|
}
|
|
if (realm && realm[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->del_secret) {
|
|
uint8_t ss[AUTH_SECRET_SIZE + 1];
|
|
uint8_t r[STUN_MAX_REALM_SIZE + 1];
|
|
STRCPY(ss, secret);
|
|
STRCPY(r, realm);
|
|
dbd->del_secret(ss, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const uint8_t *add_realm = (const uint8_t *)current_eff_realm();
|
|
const uint8_t *add_secret = (const uint8_t *)get_http_header_value(hr, HR_ADD_SECRET, "");
|
|
const char *msg = "";
|
|
if (wrong_html_name((const char *)add_secret)) {
|
|
msg = "Error: wrong secret value";
|
|
add_secret = (const uint8_t *)"";
|
|
}
|
|
if (add_secret[0]) {
|
|
add_realm = (const uint8_t *)get_http_header_value(hr, HR_ADD_REALM, current_realm());
|
|
if (!is_superuser()) {
|
|
add_realm = (const uint8_t *)current_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)current_eff_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)get_realm(NULL)->options.name;
|
|
}
|
|
if (wrong_html_name((const char *)add_realm)) {
|
|
msg = "Error: wrong realm name";
|
|
add_realm = (const uint8_t *)"";
|
|
}
|
|
if (add_realm[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_secret) {
|
|
uint8_t ss[AUTH_SECRET_SIZE + 1];
|
|
uint8_t r[STUN_MAX_REALM_SIZE + 1];
|
|
STRCPY(ss, add_secret);
|
|
STRCPY(r, add_realm);
|
|
(*dbd->set_secret)(ss, r);
|
|
}
|
|
|
|
add_secret = (const uint8_t *)"";
|
|
add_realm = (const uint8_t *)"";
|
|
}
|
|
}
|
|
|
|
write_shared_secrets_page(s, (const char *)add_secret, (const char *)add_realm, msg);
|
|
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_OS: {
|
|
if (is_as_ok(s)) {
|
|
{
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
}
|
|
|
|
if (is_superuser()) {
|
|
const uint8_t *origin = (const uint8_t *)get_http_header_value(hr, HR_DELETE_ORIGIN, NULL);
|
|
if (origin && origin[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->del_origin) {
|
|
uint8_t o[STUN_MAX_ORIGIN_SIZE + 1];
|
|
STRCPY(o, origin);
|
|
dbd->del_origin(o);
|
|
uint8_t corigin[STUN_MAX_ORIGIN_SIZE + 1];
|
|
get_canonic_origin((const char *)origin, (char *)corigin, sizeof(corigin) - 1);
|
|
dbd->del_origin(corigin);
|
|
}
|
|
}
|
|
}
|
|
|
|
const uint8_t *add_realm = (const uint8_t *)current_eff_realm();
|
|
const uint8_t *add_origin = (const uint8_t *)get_http_header_value(hr, HR_ADD_ORIGIN, "");
|
|
const char *msg = "";
|
|
uint8_t corigin[STUN_MAX_ORIGIN_SIZE + 1];
|
|
get_canonic_origin((const char *)add_origin, (char *)corigin, sizeof(corigin) - 1);
|
|
if (corigin[0]) {
|
|
add_realm = (const uint8_t *)get_http_header_value(hr, HR_ADD_REALM, current_realm());
|
|
if (!is_superuser()) {
|
|
add_realm = (const uint8_t *)current_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)current_eff_realm();
|
|
}
|
|
if (!add_realm[0]) {
|
|
add_realm = (const uint8_t *)get_realm(NULL)->options.name;
|
|
}
|
|
if (add_realm[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->add_origin) {
|
|
uint8_t o[STUN_MAX_ORIGIN_SIZE + 1];
|
|
uint8_t r[STUN_MAX_REALM_SIZE + 1];
|
|
STRCPY(o, corigin);
|
|
STRCPY(r, add_realm);
|
|
(*dbd->add_origin)(o, r);
|
|
}
|
|
|
|
add_origin = (const uint8_t *)"";
|
|
add_realm = (const uint8_t *)"";
|
|
}
|
|
}
|
|
|
|
write_origins_page(s, (const char *)add_origin, (const char *)add_realm, msg);
|
|
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_OAUTH_SHOW_KEYS: {
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else if (!is_superuser()) {
|
|
write_https_home_page(s);
|
|
} else {
|
|
const char *kid = get_http_header_value(hr, HR_OAUTH_KID, "");
|
|
write_https_oauth_show_keys(s, kid);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_OAUTH: {
|
|
if (!is_as_ok(s)) {
|
|
write_https_logon_page(s);
|
|
} else if (!is_superuser()) {
|
|
write_https_home_page(s);
|
|
} else {
|
|
|
|
{
|
|
const char *del_kid = get_http_header_value(hr, HR_DELETE_OAUTH_KID, "");
|
|
if (del_kid[0]) {
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->del_oauth_key) {
|
|
(*dbd->del_oauth_key)((const uint8_t *)del_kid);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *add_kid = "";
|
|
const char *add_ts = "0";
|
|
const char *add_lt = "0";
|
|
const char *add_ikm = "";
|
|
const char *add_tea = "";
|
|
const char *add_realm = "";
|
|
const char *msg = "";
|
|
|
|
add_kid = get_http_header_value(hr, HR_ADD_OAUTH_KID, "");
|
|
if (add_kid[0]) {
|
|
add_ikm = get_http_header_value(hr, HR_ADD_OAUTH_IKM, "");
|
|
add_ts = get_http_header_value(hr, HR_ADD_OAUTH_TS, "");
|
|
add_lt = get_http_header_value(hr, HR_ADD_OAUTH_LT, "");
|
|
add_tea = get_http_header_value(hr, HR_ADD_OAUTH_TEA, "");
|
|
add_realm = get_http_header_value(hr, HR_ADD_OAUTH_REALM, "");
|
|
|
|
int keys_ok = (add_ikm[0] != 0);
|
|
if (!keys_ok) {
|
|
msg = "You must enter the key value.";
|
|
} else {
|
|
oauth_key_data_raw key;
|
|
memset(&key, 0, sizeof(key));
|
|
STRCPY(key.kid, add_kid);
|
|
|
|
if (add_lt && add_lt[0]) {
|
|
key.lifetime = (uint32_t)strtoul(add_lt, NULL, 10);
|
|
if (key.lifetime) {
|
|
if (add_ts && add_ts[0]) {
|
|
key.timestamp = (uint64_t)strtoull(add_ts, NULL, 10);
|
|
}
|
|
if (!key.timestamp) {
|
|
key.timestamp = (uint64_t)time(NULL);
|
|
}
|
|
}
|
|
} else if (add_ts && add_ts[0]) {
|
|
key.timestamp = (uint64_t)strtoull(add_ts, NULL, 10);
|
|
}
|
|
|
|
if (add_realm && add_realm[0])
|
|
STRCPY(key.realm, add_realm);
|
|
|
|
STRCPY(key.ikm_key, add_ikm);
|
|
STRCPY(key.as_rs_alg, add_tea);
|
|
|
|
const turn_dbdriver_t *dbd = get_dbdriver();
|
|
if (dbd && dbd->set_oauth_key) {
|
|
if ((*dbd->set_oauth_key)(&key) < 0) {
|
|
msg = "Cannot insert oAuth key into the database";
|
|
} else {
|
|
add_kid = "";
|
|
add_ts = "0";
|
|
add_lt = "0";
|
|
add_ikm = "";
|
|
add_tea = "";
|
|
add_realm = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
write_https_oauth_page(s, add_kid, add_ikm, add_tea, add_ts, add_lt, add_realm, msg);
|
|
}
|
|
break;
|
|
}
|
|
case AS_FORM_TOGGLE:
|
|
if (is_as_ok(s)) {
|
|
handle_toggle_request(s, hr);
|
|
write_pc_page(s);
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
case AS_FORM_UPDATE:
|
|
if (is_as_ok(s)) {
|
|
handle_update_request(s, hr);
|
|
write_pc_page(s);
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
break;
|
|
case AS_FORM_LOGON:
|
|
if (!is_as_ok(s)) {
|
|
handle_logon_request(s, hr);
|
|
if (is_as_ok(s)) {
|
|
write_https_home_page(s);
|
|
} else {
|
|
write_https_logon_page(s);
|
|
}
|
|
} else {
|
|
write_https_home_page(s);
|
|
}
|
|
break;
|
|
case AS_FORM_LOGOUT:
|
|
handle_logout_request(s, hr);
|
|
write_https_logon_page(s);
|
|
break;
|
|
default: {
|
|
const char *realm0 = get_http_header_value(hr, HR_REALM, current_realm());
|
|
if (!is_superuser())
|
|
realm0 = current_realm();
|
|
strncpy(current_eff_realm(), realm0, STUN_MAX_REALM_SIZE);
|
|
write_https_home_page(s);
|
|
}
|
|
};
|
|
free_http_request(hr);
|
|
}
|
|
}
|
|
|
|
current_socket = NULL;
|
|
}
|
|
|
|
static void https_input_handler(ioa_socket_handle s, int event_type, ioa_net_data *data, void *arg, int can_resume) {
|
|
|
|
UNUSED_ARG(arg);
|
|
UNUSED_ARG(s);
|
|
UNUSED_ARG(event_type);
|
|
UNUSED_ARG(can_resume);
|
|
|
|
handle_https(s, data->nbh);
|
|
|
|
ioa_network_buffer_delete(adminserver.e, data->nbh);
|
|
data->nbh = NULL;
|
|
}
|
|
|
|
void https_admin_server_receive_message(struct bufferevent *bev, void *ptr) {
|
|
UNUSED_ARG(ptr);
|
|
|
|
ioa_socket_handle s = NULL;
|
|
int n = 0;
|
|
struct evbuffer *input = bufferevent_get_input(bev);
|
|
|
|
while ((n = evbuffer_remove(input, &s, sizeof(s))) > 0) {
|
|
if (n != sizeof(s)) {
|
|
fprintf(stderr, "%s: Weird HTTPS CLI buffer error: size=%d\n", __FUNCTION__, n);
|
|
continue;
|
|
}
|
|
|
|
register_callback_on_ioa_socket(adminserver.e, s, IOA_EV_READ, https_input_handler, NULL, 0);
|
|
|
|
handle_https(s, NULL);
|
|
}
|
|
}
|
|
|
|
void send_https_socket(ioa_socket_handle s) {
|
|
struct evbuffer *output = bufferevent_get_output(adminserver.https_out_buf);
|
|
if (output) {
|
|
evbuffer_add(output, &s, sizeof(s));
|
|
}
|
|
}
|
|
|
|
///////////////////////////////
|