/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include "libtelnet.h" #include #include #include #include #include #include #include #include #include "userdb.h" #include "mainrelay.h" #include "ns_turn_utils.h" #include "ns_turn_server.h" #include "ns_turn_maps.h" #include "apputils.h" #include "turn_admin_server.h" #include "http_server.h" #include "dbdrivers/dbdriver.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; /////////////////////////////// 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 - set CLI session realm", "", " ur - unset CLI session realm", "", " so - set CLI session origin", "", " uo - unset CLI session origin", "", " tc - toggle a configuration parameter", " (see pc command output for togglable param names)", "", " cc - change a configuration parameter", " (see pc command output for changeable param names)", "", " ps [username] - print sessions, with optional exact user match", "", " psp - print sessions, with partial user string match", "", " psd - 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 - 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}, {"no-loopback-peers",&turn_params.no_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,(u08bits*)s); else addr_to_string(value,(u08bits*)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;isize;i++) { if(!use_port) addr_to_string_no_port(&(value->addrs[i]),(u08bits*)s); else addr_to_string(&(value->addrs[i]),(u08bits*)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;its && 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;iranges_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)atol(pn+strlen("max-bps"))); 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)atol(pn+strlen("bps-capacity"))); 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 const char* pname(SOCKET_TYPE st) { switch(st) { case TCP_SOCKET: return "TCP"; case UDP_SOCKET: return "UDP"; case TLS_SOCKET: return "TLS"; case DTLS_SOCKET: return "DTLS"; case TENTATIVE_TCP_SOCKET: return "TCP/TLS"; default: ; }; return "UNKNOWN"; } 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) 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) 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*)turn_realloc(csarg->user_counters, (size_t)value * sizeof(size_t), csarg->users_number * sizeof(size_t)); csarg->user_names = (char**)turn_realloc(csarg->user_names, (size_t)value * sizeof(char*), csarg->users_number * sizeof(char*)); csarg->user_names[(size_t)value] = turn_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",pname(tsi->client_protocol),pname(tsi->peer_protocol)); { if(!tsi->local_addr_data.saddr[0]) addr_to_string(&(tsi->local_addr_data.addr),(u08bits*)tsi->local_addr_data.saddr); if(!tsi->remote_addr_data.saddr[0]) addr_to_string(&(tsi->remote_addr_data.addr),(u08bits*)tsi->remote_addr_data.saddr); if(!tsi->relay_addr_data_ipv4.saddr[0]) addr_to_string(&(tsi->relay_addr_data_ipv4.addr),(u08bits*)tsi->relay_addr_data_ipv4.saddr); if(!tsi->relay_addr_data_ipv6.saddr[0]) addr_to_string(&(tsi->relay_addr_data_ipv6.addr),(u08bits*)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;imain_peers_size;++i) { if(!(tsi->main_peers_data[i].saddr[0])) addr_to_string(&(tsi->main_peers_data[i].addr),(u08bits*)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;iextra_peers_size;++i) { if(!(tsi->extra_peers_data[i].saddr[0])) addr_to_string(&(tsi->extra_peers_data[i].addr),(u08bits*)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, %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) turn_free(arg.user_counters,sizeof(size_t)*arg.users_number); if(arg.user_names) { size_t i; for(i=0;ioptions.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; } turn_free(cs,sizeof(struct cli_session)); } } 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*)turn_malloc(len+1); ns_bcopy(buf0,buf,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(strcmp(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); } turn_free(buf,len+1); } 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*)turn_malloc(sizeof(struct cli_session)); ns_bzero(clisession,sizeof(struct cli_session)); clisession->rp = get_realm(NULL); set_socket_options_fd(fd, 1, 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); debug_ptr_add(clisession->bev); 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); } } } 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 ); 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); } if(use_cli) { if(!cli_addr_set) { if(make_ioa_addr((const u08bits*)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, SOCK_STREAM, 0); 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)<0) { perror("Cannot bind CLI socket to addr"); char saddr[129]; addr_to_string(&cli_addr,(u08bits*)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); 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*)turn_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); turn_free(old,sizeof(struct turn_session_info)); 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*)turn_malloc(sizeof(struct turn_session_info)); turn_session_info_init(tsi); } else { turn_session_info_clean(tsi); } } if(tsi) { turn_session_info_clean(tsi); turn_free(tsi,sizeof(struct turn_session_info)); } } 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_TS "oauth_ts" #define HR_ADD_OAUTH_LT "oauth_lt" #define HR_ADD_OAUTH_IKM "oauth_ikm" #define HR_ADD_OAUTH_RS_KEY "oauth_rs_key" #define HR_ADD_OAUTH_AUTH_KEY "oauth_auth_key" #define HR_ADD_OAUTH_HKDF "oauth_hkdf" #define HR_ADD_OAUTH_TEA "oauth_tea" #define HR_ADD_OAUTH_AA "oauth_aa" #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 "TURN Server
https admin connection
\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]; STRCPY(sbat,__bold_admin_title); 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," admin user: %s
\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: %s
\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: %s
\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,"\r\n\r\n \r\n "); str_buffer_append(sb,admin_title); str_buffer_append(sb,"\r\n \r\n \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,"
home page
\r\n
logout
\r\n"); str_buffer_append(sb,"
\r\n"); } static void https_finish_page(struct str_buffer *sb, ioa_socket_handle s, int cclose) { str_buffer_append(sb,"\r\n\r\n"); send_str_from_ioa_socket_tcp(s,"HTTP/1.1 200 OK\r\nServer: "); 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"); } 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,"
To use the HTTPS admin connection, you have to set the database table admin_user with the admin user accounts.
\r\n"); } else { str_buffer_append(sb,"

\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
Admin user information: user name:

password:


\r\n"); str_buffer_append(sb,"
\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,"
\r\n"); str_buffer_append(sb,"
Actions:\r\n"); str_buffer_append(sb," Realm name: "); } else { str_buffer_append(sb,"> "); } str_buffer_append(sb,"
"); str_buffer_append(sb,"
Configuration Parameters"); str_buffer_append(sb,"
TURN Sessions"); str_buffer_append(sb,"
Users"); str_buffer_append(sb,"
Shared Secrets (for TURN REST API)"); str_buffer_append(sb,"
Origins"); if(is_superuser()) { str_buffer_append(sb,"
oAuth keys"); } str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\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,"%s%s\r\n",name,get_flag(flag)); } else { sbprintf(sb,"%s%s\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,"%s%lu\r\n",name,value); } else { sbprintf(sb,"%s \r\n",name); } } else { if(value) { sbprintf(sb,"%s
\r\n",name,form_names[AS_FORM_UPDATE].name,HR_UPDATE_PARAMETER,param_name,param_name,value); } else { sbprintf(sb,"%s
\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,"%s%s\r\n",name,value); } else { sbprintf(sb,"%s
\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 %s %s\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,(u08bits*)s); else addr_to_string(value,(u08bits*)s); sbprintf(sb," %s %s\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;isize;i++) { if(!use_port) addr_to_string_no_port(&(value->addrs[i]),(u08bits*)s); else addr_to_string(&(value->addrs[i]),(u08bits*)s); sbprintf(sb," %s %s\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,"delete",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;iranges_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," %s %s [%s] %s\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," %s %s %s\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," Add %s",name); sbprintf(sb,"
IP range:",form_names[AS_FORM_UPDATE].name,HR_ADD_IP_KIND,kind,HR_ADD_IP); sbprintf(sb,"Realm: "); sbprintf(sb,"
\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)atol(value)); } else if(strstr(pn,"bps-capacity")==pn) { set_bps_capacity((band_limit_t)atol(value)); } } { 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((u08bits*)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((u08bits*)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)atol(value); dbd->set_realm_option_one((u08bits*)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,"
"); } 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,"
\r\n"); str_buffer_append(sb,"Configuration Parameters:

\r\n"); str_buffer_append(sb,"\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); https_print_uint(sb,(unsigned long)getuid(),"process user ID",0); https_print_uint(sb,(unsigned long)getgid(),"process group ID",0); { 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); if(turn_params.shatype == SHATYPE_SHA256) https_print_str(sb,"SHA256","SHA type",0); else https_print_str(sb,"SHA1","SHA type",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_sslv3 && !turn_params.no_tls),"SSLv3",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.no_loopback_peers,"no-loopback-peers","no-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[0]) { https_print_str(sb,turn_params.redis_statsdb,"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
ParameterValue
\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) 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) 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,""); str_buffer_append_sz(sb,(size_t)(csarg->counter+1)); str_buffer_append(sb,""); str_buffer_append_sid(sb,tsi->id); str_buffer_append(sb,"
cancel"); str_buffer_append(sb,""); str_buffer_append(sb,(char*)tsi->username); str_buffer_append(sb,""); str_buffer_append(sb,tsi->realm); str_buffer_append(sb,""); str_buffer_append(sb,tsi->origin); str_buffer_append(sb,""); 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,""); 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,""); str_buffer_append(sb,pname(tsi->client_protocol)); str_buffer_append(sb,""); str_buffer_append(sb,pname(tsi->peer_protocol)); str_buffer_append(sb,""); { if(!tsi->local_addr_data.saddr[0]) addr_to_string(&(tsi->local_addr_data.addr),(u08bits*)tsi->local_addr_data.saddr); if(!tsi->remote_addr_data.saddr[0]) addr_to_string(&(tsi->remote_addr_data.addr),(u08bits*)tsi->remote_addr_data.saddr); if(!tsi->relay_addr_data_ipv4.saddr[0]) addr_to_string(&(tsi->relay_addr_data_ipv4.addr),(u08bits*)tsi->relay_addr_data_ipv4.saddr); if(!tsi->relay_addr_data_ipv6.saddr[0]) addr_to_string(&(tsi->relay_addr_data_ipv6.addr),(u08bits*)tsi->relay_addr_data_ipv6.saddr); str_buffer_append(sb,tsi->remote_addr_data.saddr); str_buffer_append(sb,""); str_buffer_append(sb,tsi->local_addr_data.saddr); str_buffer_append(sb,""); str_buffer_append(sb,tsi->relay_addr_data_ipv4.saddr); str_buffer_append(sb,""); str_buffer_append(sb,tsi->relay_addr_data_ipv6.saddr); str_buffer_append(sb,""); str_buffer_append(sb,get_flag(tsi->enforce_fingerprints)); str_buffer_append(sb,""); str_buffer_append(sb,get_flag(tsi->is_mobile)); str_buffer_append(sb,""); str_buffer_append(sb,tsi->tls_method); str_buffer_append(sb,""); str_buffer_append(sb,tsi->tls_cipher); str_buffer_append(sb,""); str_buffer_append_sz(sb,(size_t)tsi->bps); str_buffer_append(sb,""); { 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,""); } { 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,""); } if(tsi->main_peers_size) { size_t i; for(i=0;imain_peers_size;++i) { if(!(tsi->main_peers_data[i].saddr[0])) addr_to_string(&(tsi->main_peers_data[i].addr),(u08bits*)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;iextra_peers_size;++i) { if(!(tsi->extra_peers_data[i].saddr[0])) addr_to_string(&(tsi->extra_peers_data[i].addr),(u08bits*)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,""); } } 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,"
\r\n"); str_buffer_append(sb,"
Filter:\r\n"); str_buffer_append(sb,"
Realm name: "); str_buffer_append(sb," Client protocol: "); str_buffer_append(sb," User name contains:

"); str_buffer_append(sb," Max number of output sessions in the page:
"); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
TURN Sessions:

\r\n"); str_buffer_append(sb,"\r\n"); size_t total_sz = https_print_sessions(sb,client_protocol,user_pattern,max_sessions,cs); str_buffer_append(sb,"\r\n
NSession IDUserRealmOriginAge, secsExpires, secsClient protocolRelay protocolClient addrServer addrRelay addr (IPv4)Relay addr (IPv6)FingerprintsMobileTLS methodTLS cipherBPS (allocated)PacketsRatePeers
\r\n"); str_buffer_append(sb,"
Total sessions = "); str_buffer_append_sz(sb,total_sz); str_buffer_append(sb,"
\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((u08bits*)current_eff_realm(),&users,&realms); size_t sz = get_secrets_list_size(&users); size_t i; for(i=0;i"); str_buffer_append_sz(sb,i+1); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&users,i)); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&realms,i)); str_buffer_append(sb,""); } str_buffer_append(sb," delete"); str_buffer_append(sb,""); str_buffer_append(sb,""); ++ret; } clean_secrets_list(&users); clean_secrets_list(&realms); } return ret; } static void write_users_page(ioa_socket_handle s, const u08bits *add_user, const u08bits *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,"
\r\n"); str_buffer_append(sb,"
Filter:\r\n"); str_buffer_append(sb,"
Realm name: "); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
User:\r\n"); if(msg && msg[0]) { str_buffer_append(sb,"
"); str_buffer_append(sb,msg); str_buffer_append(sb,"

"); } str_buffer_append(sb,"
Realm name:
\r\n"); str_buffer_append(sb,"
User name:
\r\n"); str_buffer_append(sb,"
Password:
\r\n"); str_buffer_append(sb,"
Confirm password:

\r\n"); if(turn_params.shatype == SHATYPE_SHA256) str_buffer_append(sb,"SHA type: SHA256
\r\n"); else str_buffer_append(sb,"SHA type: SHA1
\r\n"); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
Users:

\r\n"); str_buffer_append(sb,"\r\n"); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); } str_buffer_append(sb,""); str_buffer_append(sb,"\r\n"); size_t total_sz = https_print_users(sb); str_buffer_append(sb,"\r\n
NNameRealm
\r\n"); str_buffer_append(sb,"
Total users = "); str_buffer_append_sz(sb,total_sz); str_buffer_append(sb,"
\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((u08bits*)current_eff_realm(),&secrets,&realms); size_t sz = get_secrets_list_size(&secrets); size_t i; for(i=0;i"); str_buffer_append_sz(sb,i+1); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&secrets,i)); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&realms,i)); str_buffer_append(sb,""); } str_buffer_append(sb," delete"); str_buffer_append(sb,""); str_buffer_append(sb,""); ++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,"
\r\n"); str_buffer_append(sb,"
Filter:\r\n"); str_buffer_append(sb,"
Realm name: "); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
Secret:\r\n"); if(msg && msg[0]) { str_buffer_append(sb,"
"); str_buffer_append(sb,msg); str_buffer_append(sb,"

"); } str_buffer_append(sb,"
Realm name:
\r\n"); str_buffer_append(sb,"
Secret:
\r\n"); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
Shared secrets:

\r\n"); str_buffer_append(sb,"\r\n"); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); } str_buffer_append(sb,""); str_buffer_append(sb,"\r\n"); size_t total_sz = https_print_secrets(sb); str_buffer_append(sb,"\r\n
NValueRealm
\r\n"); str_buffer_append(sb,"
Total secrets = "); str_buffer_append_sz(sb,total_sz); str_buffer_append(sb,"
\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((u08bits*)current_eff_realm(),&origins,&realms); size_t sz = get_secrets_list_size(&origins); size_t i; for(i=0;i"); str_buffer_append_sz(sb,i+1); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&origins,i)); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&realms,i)); str_buffer_append(sb,""); } if(is_superuser()) { str_buffer_append(sb," delete"); str_buffer_append(sb,""); } str_buffer_append(sb,""); ++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,"
\r\n"); str_buffer_append(sb,"
Filter:\r\n"); str_buffer_append(sb,"
Realm name: "); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); if(is_superuser()) { str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
Origin:\r\n"); if(msg && msg[0]) { str_buffer_append(sb,"
"); str_buffer_append(sb,msg); str_buffer_append(sb,"

"); } str_buffer_append(sb,"
Realm name:
\r\n"); str_buffer_append(sb,"
Origin:
\r\n"); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); } str_buffer_append(sb,"
Origins:

\r\n"); str_buffer_append(sb,"\r\n"); str_buffer_append(sb,""); if(!current_eff_realm()[0]) { str_buffer_append(sb,""); } if(is_superuser()) { str_buffer_append(sb,""); } str_buffer_append(sb,"\r\n"); size_t total_sz = https_print_origins(sb); str_buffer_append(sb,"\r\n
NValueRealm
\r\n"); str_buffer_append(sb,"
Total origins = "); str_buffer_append_sz(sb,total_sz); str_buffer_append(sb,"
\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,hkdfs,teas,aas,tss,lts; init_secrets_list(&kids); init_secrets_list(&hkdfs); init_secrets_list(&teas); init_secrets_list(&aas); init_secrets_list(&tss); init_secrets_list(<s); dbd->list_oauth_keys(&kids,&hkdfs,&teas,&aas,&tss,<s); size_t sz = get_secrets_list_size(&kids); size_t i; for(i=0;i"); str_buffer_append_sz(sb,i+1); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&kids,i)); str_buffer_append(sb,""); str_buffer_append(sb," show "); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&tss,i)); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(<s,i)); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&hkdfs,i)); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&teas,i)); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,get_secrets_list_elem(&aas,i)); str_buffer_append(sb,""); { str_buffer_append(sb," delete"); str_buffer_append(sb,""); } str_buffer_append(sb,""); ++ret; } clean_secrets_list(&kids); clean_secrets_list(&hkdfs); clean_secrets_list(&teas); clean_secrets_list(&aas); } 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,"back to oauth list

\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 u08bits*)kid,&key)<0) { str_buffer_append(sb,"data retrieval error"); } else { oauth_key_data okd; ns_bzero(&okd,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; ns_bzero(&okey,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,"\r\n"); if(key.ikm_key[0]) { str_buffer_append(sb,"\r\n"); } if(okey.as_rs_key_size) { size_t as_rs_key_size = 0; char *as_rs_key = (char*)base64_encode((unsigned char*)okey.as_rs_key,okey.as_rs_key_size,&as_rs_key_size); if(as_rs_key) { str_buffer_append(sb,"\r\n"); turn_free(as_rs_key,as_rs_key_size); } } if(okey.auth_key_size) { size_t auth_key_size = 0; char *auth_key = (char*)base64_encode((unsigned char*)okey.auth_key,okey.auth_key_size,&auth_key_size); if(auth_key) { str_buffer_append(sb,"\r\n"); turn_free(auth_key,auth_key_size); } } str_buffer_append(sb,"
Input Keying Material:"); str_buffer_append(sb,key.ikm_key); str_buffer_append(sb,"
AS-RS key:"); str_buffer_append(sb,as_rs_key); str_buffer_append(sb,"
AUTH key:"); str_buffer_append(sb,auth_key); str_buffer_append(sb,"
\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_hkdf_hash_func, const char* add_tea, const char* add_aa, const char *add_ts, const char* add_lt, const char *add_rs_key, const char *add_auth_key, 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,"
\r\n"); str_buffer_append(sb,"
oAuth key:\r\n"); if(msg && msg[0]) { str_buffer_append(sb,"
"); str_buffer_append(sb,msg); str_buffer_append(sb,"

"); } str_buffer_append(sb,"\r\n\r\n
"); { if(!add_kid) add_kid=""; str_buffer_append(sb,"
KID (required):
\r\n"); } str_buffer_append(sb,"
"); { if(!add_ts) add_ts=""; str_buffer_append(sb,"
Timestamp, secs (optional):
\r\n"); } str_buffer_append(sb,"
"); { if(!add_lt) add_lt=""; str_buffer_append(sb,"
Lifetime, secs (optional):
\r\n"); } str_buffer_append(sb,"
"); { str_buffer_append(sb,"
Hash key derivation function (optional):
\r\n"); if(!add_hkdf_hash_func || !add_hkdf_hash_func[0]) add_hkdf_hash_func = "SHA-256"; str_buffer_append(sb,"SHA-1\r\n
\r\n"); str_buffer_append(sb,"SHA-256\r\n
\r\n"); } str_buffer_append(sb,"
"); { if(!add_ikm) add_ikm = ""; str_buffer_append(sb,"
Base64-encoded input keying material (optional):
"); str_buffer_append(sb,"
\r\n"); } str_buffer_append(sb,"
"); { str_buffer_append(sb,"
Token encryption algorithm (required):
\r\n"); if(!add_tea || !add_tea[0]) add_tea = "AES-256-CBC"; str_buffer_append(sb,"AES-128-CBC\r\n
\r\n"); str_buffer_append(sb,"AES-256-CBC\r\n
\r\n"); str_buffer_append(sb,"AEAD-AES-128-GCM\r\n
\r\n"); str_buffer_append(sb,"AEAD-AES-256-GCM\r\n
\r\n"); } str_buffer_append(sb,"
"); { if(!add_rs_key) add_rs_key = ""; str_buffer_append(sb,"
Base64-encoded AS-RS key (optional):
"); str_buffer_append(sb,"
\r\n"); } str_buffer_append(sb,"
"); { str_buffer_append(sb,"
Token authentication algorithm (required if no AEAD used):
\r\n"); if(!add_aa || !add_aa[0]) add_aa = "HMAC-SHA-256-128"; str_buffer_append(sb,"HMAC-SHA-256-128\r\n
\r\n"); str_buffer_append(sb,"HMAC-SHA-256\r\n
\r\n"); str_buffer_append(sb,"HMAC-SHA-1\r\n
\r\n"); } str_buffer_append(sb,"
"); { if(!add_auth_key) add_auth_key = ""; str_buffer_append(sb,"
Base64-encoded AUTH key (optional):
"); str_buffer_append(sb,"
\r\n"); } str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
"); str_buffer_append(sb,"
\r\n"); str_buffer_append(sb,"
\r\n"); } str_buffer_append(sb,"
OAuth keys:

\r\n"); str_buffer_append(sb,"\r\n"); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,""); str_buffer_append(sb,"\r\n"); size_t total_sz = https_print_oauth_keys(sb); str_buffer_append(sb,"\r\n
NKIDkeysTimestamp, secsLifetime,secsHash key derivation functionToken encryption algorithmToken authentication algorithm
\r\n"); str_buffer_append(sb,"
Total oAuth keys = "); str_buffer_append_sz(sb,total_sz); str_buffer_append(sb,"
\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 { u08bits 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 { u08bits 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*)turn_malloc(sizeof(struct admin_session)); ns_bzero(as,sizeof(struct admin_session)); s->special_session = as; s->special_session_size = sizeof(struct admin_session); } if(!(as->as_ok) && uname && 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 u08bits*)uname,(u08bits*)realm,password)>=0) { if(!strcmp(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; 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__); } 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 u08bits *user = (const u08bits*)get_http_header_value(hr, HR_DELETE_USER, NULL); if(user && user[0]) { const u08bits *realm = (const u08bits*)get_http_header_value(hr, HR_DELETE_REALM, ""); if(!is_superuser()) { realm = (const u08bits*)current_realm(); } if(realm && realm[0]) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->del_user) { u08bits u[STUN_MAX_USERNAME_SIZE+1]; u08bits r[STUN_MAX_REALM_SIZE+1]; STRCPY(u,user); STRCPY(r,realm); dbd->del_user(u,r); } } } } const u08bits *add_realm = (const u08bits*)current_eff_realm(); const u08bits *add_user = (const u08bits*)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 u08bits*)""; } if(add_user[0]) { add_realm = (const u08bits*)get_http_header_value(hr, HR_ADD_REALM, current_realm()); if(!is_superuser()) { add_realm = (const u08bits*)current_realm(); } if(!add_realm[0]) { add_realm=(const u08bits*)current_eff_realm(); } if(!add_realm[0]) { add_realm = (const u08bits*)get_realm(NULL)->options.name; } if(wrong_html_name((const char*)add_realm)) { msg = "Error: wrong realm name"; add_realm = (const u08bits*)""; } if(add_realm[0]) { const u08bits *pwd = (const u08bits*)get_http_header_value(hr, HR_PASSWORD, NULL); const u08bits *pwd1 = (const u08bits*)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]; { u08bits u[STUN_MAX_USERNAME_SIZE+1]; u08bits r[STUN_MAX_REALM_SIZE+1]; u08bits 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, turn_params.shatype); size_t i = 0; size_t sz = get_hmackey_size(turn_params.shatype); 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 u08bits*)""; add_user=(const u08bits*)""; } } 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 u08bits *secret = (const u08bits*)get_http_header_value(hr, HR_DELETE_SECRET, NULL); if(secret && secret[0]) { const u08bits *realm = (const u08bits*)get_http_header_value(hr, HR_DELETE_REALM, NULL); if(!is_superuser()) { realm = (const u08bits*)current_realm(); } if(realm && realm[0]) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->del_secret) { u08bits ss[AUTH_SECRET_SIZE+1]; u08bits r[STUN_MAX_REALM_SIZE+1]; STRCPY(ss,secret); STRCPY(r,realm); dbd->del_secret(ss,r); } } } } const u08bits *add_realm = (const u08bits*)current_eff_realm(); const u08bits *add_secret = (const u08bits*)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 u08bits*)""; } if(add_secret[0]) { add_realm = (const u08bits*)get_http_header_value(hr, HR_ADD_REALM, current_realm()); if(!is_superuser()) { add_realm = (const u08bits*)current_realm(); } if(!add_realm[0]) { add_realm=(const u08bits*)current_eff_realm(); } if(!add_realm[0]) { add_realm = (const u08bits*)get_realm(NULL)->options.name; } if(wrong_html_name((const char*)add_realm)) { msg = "Error: wrong realm name"; add_realm = (const u08bits*)""; } if(add_realm[0]) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->set_secret) { u08bits ss[AUTH_SECRET_SIZE+1]; u08bits r[STUN_MAX_REALM_SIZE+1]; STRCPY(ss,add_secret); STRCPY(r,add_realm); (*dbd->set_secret)(ss, r); } add_secret=(const u08bits*)""; add_realm=(const u08bits*)""; } } 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 u08bits *origin = (const u08bits*)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) { u08bits o[STUN_MAX_ORIGIN_SIZE+1]; STRCPY(o,origin); dbd->del_origin(o); u08bits corigin[STUN_MAX_ORIGIN_SIZE+1]; get_canonic_origin((const char *)origin, (char *)corigin, sizeof(corigin)-1); dbd->del_origin(corigin); } } } const u08bits *add_realm = (const u08bits*)current_eff_realm(); const u08bits *add_origin = (const u08bits*)get_http_header_value(hr, HR_ADD_ORIGIN, ""); const char* msg = ""; u08bits corigin[STUN_MAX_ORIGIN_SIZE+1]; get_canonic_origin((const char *)add_origin, (char *)corigin, sizeof(corigin)-1); if(corigin[0]) { add_realm = (const u08bits*)get_http_header_value(hr, HR_ADD_REALM, current_realm()); if(!is_superuser()) { add_realm = (const u08bits*)current_realm(); } if(!add_realm[0]) { add_realm=(const u08bits*)current_eff_realm(); } if(!add_realm[0]) { add_realm = (const u08bits*)get_realm(NULL)->options.name; } if(add_realm[0]) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->add_origin) { u08bits o[STUN_MAX_ORIGIN_SIZE+1]; u08bits r[STUN_MAX_REALM_SIZE+1]; STRCPY(o,corigin); STRCPY(r,add_realm); (*dbd->add_origin)(o, r); } add_origin=(const u08bits*)""; add_realm=(const u08bits*)""; } } 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 u08bits*)del_kid); } } } const char* add_kid = ""; const char* add_ts = "0"; const char* add_lt = "0"; const char* add_ikm = ""; const char *add_rs_key = ""; const char *add_auth_key = ""; const char* add_hkdf_hash_func = ""; const char* add_tea = ""; const char* add_aa = ""; 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_rs_key = get_http_header_value(hr,HR_ADD_OAUTH_RS_KEY,""); add_auth_key = get_http_header_value(hr,HR_ADD_OAUTH_AUTH_KEY,""); add_ts = get_http_header_value(hr,HR_ADD_OAUTH_TS,""); add_lt = get_http_header_value(hr,HR_ADD_OAUTH_LT,""); add_hkdf_hash_func = get_http_header_value(hr,HR_ADD_OAUTH_HKDF,""); add_tea = get_http_header_value(hr,HR_ADD_OAUTH_TEA,""); add_aa = get_http_header_value(hr,HR_ADD_OAUTH_AA,""); int keys_ok = 0; if(add_ikm[0] && add_hkdf_hash_func[0]) { keys_ok = 1; } else if(add_rs_key[0] && add_auth_key[0]) { keys_ok = 1; } else if(strstr(add_tea,"AEAD") && add_rs_key[0]) { keys_ok = 1; } if(!keys_ok) { msg = "Provided information is insufficient for the oAuth key generation."; } else { oauth_key_data_raw key; ns_bzero(&key,sizeof(key)); STRCPY(key.kid,add_kid); if(add_lt && add_lt[0]) { key.lifetime = (u32bits)strtoul(add_lt,NULL,10); if(key.lifetime) { if(add_ts && add_ts[0]) { key.timestamp = (u64bits)strtoull(add_ts,NULL,10); } if(!key.timestamp) { key.timestamp = (u64bits)time(NULL); } } } else if(add_ts && add_ts[0]) { key.timestamp = (u64bits)strtoull(add_ts,NULL,10); } STRCPY(key.ikm_key,add_ikm); STRCPY(key.hkdf_hash_func,add_hkdf_hash_func); STRCPY(key.as_rs_alg,add_tea); STRCPY(key.auth_alg,add_aa); STRCPY(key.as_rs_key,add_rs_key); STRCPY(key.auth_key,add_auth_key); if(strstr(key.as_rs_alg,"AEAD")) key.auth_alg[0]=0; 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_hkdf_hash_func = ""; add_tea = ""; add_aa = ""; add_rs_key = ""; add_auth_key = ""; } } } } write_https_oauth_page(s,add_kid,add_ikm,add_hkdf_hash_func,add_tea,add_aa,add_ts,add_lt,add_rs_key,add_auth_key,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)); } } ///////////////////////////////