diff options
Diffstat (limited to 'raptorsmiface/libraptorsmiface.c')
| -rw-r--r-- | raptorsmiface/libraptorsmiface.c | 1278 |
1 files changed, 1278 insertions, 0 deletions
diff --git a/raptorsmiface/libraptorsmiface.c b/raptorsmiface/libraptorsmiface.c new file mode 100644 index 00000000..bb934b39 --- /dev/null +++ b/raptorsmiface/libraptorsmiface.c @@ -0,0 +1,1278 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + (c) 2012 Timothy Pearson + (c) 2012 Raptor Engineering +*/ + +#define _GNU_SOURCE +#define HAVE_STDINT_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> + +#include <netdb.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <pwd.h> +#include <grp.h> +#include <time.h> + +#define list_delete mysql_list_delete +#include <mysql/mysql.h> +#undef list_delete + +#include "list.h" +#include "libraptorsmiface.h" + +#define STATISTICS_SERVER_START_EVENT 0 +#define STATISTICS_SERVER_STOP_EVENT 1 +#define STATISTICS_NEW_CONNECTION_EVENT 2 +#define STATISTICS_CONNECTION_STATUS_EVENT 3 +#define STATISTICS_DISCONNECTION_EVENT 4 + +#define RAPTORSMIFACE_CFG_DATABASE "Database" +#define RAPTORSMIFACE_CFG_DATABASE_SERVER "Server" +#define RAPTORSMIFACE_CFG_DATABASE_NAME "Database" +#define RAPTORSMIFACE_CFG_DATABASE_USER "User" +#define RAPTORSMIFACE_CFG_DATABASE_PASSWORD "Password" + +#define RAPTORSMIFACE_CFG_DATABASE_SCHEMA_VERSION 1 + +char *server = NULL; +char *user = NULL; +char *password = NULL; +char *database = NULL; + +char *local_machine_fqdn = NULL; + +void dprint(const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + +#if 0 + vprintf(fmt, argp); +#else + char debug[512]; + vsprintf(debug, fmt, argp); + FILE *fp = fopen("/raptorsmiface.debug", "a"); + if (fp != NULL) + { + fputs(debug, fp); + fclose(fp); + } +#endif + + va_end(argp); +} + +void raptorsmiface_config_read_database(int file, struct list* param_n, struct list* param_v) { + int i; + char* buf; + char* temp_buf; + + // Set defaults + if (!server) server = strdup("localhost"); + if (!user) user = strdup("remotelab"); + if (!password) password = strdup(""); + if (!database) database = strdup("remotelab_sm"); + + list_clear(param_v); + list_clear(param_n); + + file_read_section(file, RAPTORSMIFACE_CFG_DATABASE, param_n, param_v); + for (i = 0; i < param_n->count; i++) { + buf = (char*)list_get_item(param_n, i); + if (0 == g_strcasecmp(buf, RAPTORSMIFACE_CFG_DATABASE_SERVER)) { + free(server); + server = strdup((char*)list_get_item(param_v, i)); + } + if (0 == g_strcasecmp(buf, RAPTORSMIFACE_CFG_DATABASE_NAME)) { + free(database); + database = strdup((char*)list_get_item(param_v, i)); + } + if (0 == g_strcasecmp(buf, RAPTORSMIFACE_CFG_DATABASE_USER)) { + free(user); + user = strdup((char*)list_get_item(param_v, i)); + } + if (0 == g_strcasecmp(buf, RAPTORSMIFACE_CFG_DATABASE_PASSWORD)) { + free(password); + password = strdup((char*)list_get_item(param_v, i)); + } + } + + g_printf("raptorsmiface configuration:\r\n"); + g_printf("\tServer: %s\r\n", server); + g_printf("\tDatabase: %s\r\n", database); + g_printf("\tUser: %s\r\n", user); +} + +void read_ini_configuration() { + int fd; + struct list* sec; + struct list* param_n; + struct list* param_v; + + /* set global variables */ + local_machine_fqdn = raptor_sm_get_local_machine_fqdn(); + + /* open configuration file */ + char cfg_file[256]; + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + + fd = g_file_open(cfg_file); + if (-1 == fd) { + dprint("[ERROR] Unable to open configuration file [%s]", cfg_file); + return; + } + + sec = list_create(); + sec->auto_free = 1; + file_read_sections(fd, sec); + param_n = list_create(); + param_n->auto_free = 1; + param_v = list_create(); + param_v->auto_free = 1; + + /* read database config */ + raptorsmiface_config_read_database(fd, param_n, param_v); + + /* cleanup */ + list_delete(sec); + list_delete(param_v); + list_delete(param_n); + g_file_close(fd); +} + +MYSQL * connect_if_needed() { + MYSQL *conn = mysql_init(NULL); + read_ini_configuration(); + if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) { + dprint("[ERROR] MySQL connection FAILED [%s]\n\r", mysql_error(conn)); + conn = 0; + } + else { + // Check schema version + char* query; + MYSQL_RES *res; + MYSQL_ROW row; + asprintf(&query, "SELECT value FROM dbschema WHERE skey='revision'"); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + dprint("[ERROR] MySQL connection FAILED [%s]\n\r", mysql_error(conn)); + conn = 0; + } + else { + free(query); + res = mysql_store_result(conn); + if ((row = mysql_fetch_row(res)) == NULL) { + dprint("[ERROR] Mandatory schema version key not found\n\r"); + conn = 0; + } + else if (!row[0]) { + dprint("[ERROR] Mandatory schema version key not found\n\r"); + conn = 0; + } + else { + int schema_version = atoi(row[0]); + if (schema_version != RAPTORSMIFACE_CFG_DATABASE_SCHEMA_VERSION) { + dprint("[ERROR] Schema version key mismatch (%d:%d)\n\r", schema_version, RAPTORSMIFACE_CFG_DATABASE_SCHEMA_VERSION); + conn = 0; + } + } + } + } + return conn; +} + +char* get_mysql_escaped_string(MYSQL *sqlcn, char* rawstr) { + unsigned int minlen = strlen(rawstr); + unsigned int maxlen = ((minlen*2)+1); + char* escstr = malloc(maxlen*sizeof(char)); + mysql_real_escape_string(sqlcn, escstr, rawstr, minlen); + return escstr; +} + +char mutex; +int mysql_query_internal(MYSQL *conn, const char * query) { + // For some reason this can hang rather badly + // It might be related to concurrent access to the same conn object though + return mysql_query(conn, query); +} + +char* get_group_for_user(char* username) { + struct passwd* pwd; + pwd = getpwnam(username); + if (!pwd) { + return NULL; + } + gid_t groupid = pwd->pw_gid; + struct group* primarygroup; + primarygroup = getgrgid(groupid); + if (!primarygroup) { + return NULL; + } + + return strdup(primarygroup->gr_name); +} + +int raptor_sm_get_uid_for_user(char* username) { + struct passwd *pwd = calloc(1, sizeof(struct passwd)); + if (pwd == NULL) { + return -1; + } + size_t buffer_len = sysconf(_SC_GETPW_R_SIZE_MAX) * sizeof(char); + char *buffer = malloc(buffer_len); + if (buffer == NULL) { + return -2; + } + getpwnam_r(username, pwd, buffer, buffer_len, &pwd); + if (pwd == NULL) { + return -3; + } + uid_t uid = pwd->pw_uid; + free(buffer); + free(pwd); + return uid; +} + +char raptor_sm_deallocate_session(char* username) { + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_RES *svr_res; + MYSQL_ROW svr_row; + MYSQL_RES *cnt_res; + MYSQL_ROW cnt_row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return 1; + } + + int display = raptor_sm_get_display_for_username(username); + char* hostname = raptor_sm_get_hostname_for_username(username, false); + pid_t serverpid = raptor_sm_get_pid_for_username(username, RAPTOR_SM_SERVER_PID_FIELD); + if (serverpid >= 0) { + // Verify non-existence of PID on remote server before removing session information from the database + char* ip = raptor_sm_get_ip_for_hostname(hostname, 0); + char* command_string; + asprintf(&command_string, "ssh root@%s \'ps -p %d | grep %d\'", ip, serverpid, serverpid); + FILE *fp; + char output[1024]; + // Open the command for reading + fp = popen(command_string, "r"); + if (fp == NULL) { + free(ip); + mysql_close(conn); + return -1; + } + // Read the output a line at a time + fgets(output, sizeof(output)-1, fp); + // Close output + pclose(fp); + free(command_string); + free(ip); + if (strcmp(output, "") != 0) { + mysql_free_result(res); + mysql_close(conn); + return 0; + } + } + +#ifndef RAPTOR_SM_DISABLE_KERBEROS + char* command_string; + char* ip = raptor_sm_get_ip_for_hostname(hostname, 0); + asprintf(&command_string, "ssh root@%s \'rm -f /tmp/krb5cc_%d\'", ip, raptor_sm_get_uid_for_user(username)); + dprint("Running command %s...\n\r", command_string); + system(command_string); + free(command_string); + free(ip); +#endif + + // Remove the user from the system + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "DELETE FROM sessions WHERE username='%s'", safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(hostname); + free(query); + mysql_close(conn); + return 2; + } + else { + free(query); + + // Insert connection information into the statistics database + char* safe_servername = get_mysql_escaped_string(conn, hostname); + char* safe_username = get_mysql_escaped_string(conn, username); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid, username) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d', '%s')", timestamp, STATISTICS_DISCONNECTION_EVENT, safe_local_machine_fqdn, safe_servername, display, -1, safe_username); + free(safe_servername); + free(safe_username); + free(safe_local_machine_fqdn); + free(hostname); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + + mysql_close(conn); + return 0; + } +} + +char* raptor_sm_allocate_session(char* username) { + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_RES *svr_res; + MYSQL_ROW svr_row; + MYSQL_RES *per_res; + MYSQL_ROW per_row; + MYSQL_RES *cnt_res; + MYSQL_ROW cnt_row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return strdup("ERROR"); + } + + // Verify that this user is not already on the system + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "SELECT servername FROM sessions WHERE username='%s'", safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return strdup("ERROR"); + } + else { + free(query); + res = mysql_store_result(conn); + if ((row = mysql_fetch_row(res)) == NULL) { + // User is not on a system + // Find the least utilized node + if (mysql_query_internal(conn, "SELECT name FROM servers WHERE online='1'")) { + // Server error + mysql_free_result(res); + mysql_close(conn); + return strdup("ERROR"); + } + else { + svr_res = mysql_store_result(conn); + + // Get group for user + char* groupname = get_group_for_user(username); + if (!groupname) { + return strdup("ERROR"); + } + char* safe_groupname = get_mysql_escaped_string(conn, groupname); + free(groupname); + // Get the list of allowed nodes for this group + asprintf(&query, "SELECT server FROM allowed_servers WHERE groupname='%s'", safe_groupname); + free(safe_groupname); + if (mysql_query_internal(conn, query)) { + // Server error + mysql_free_result(res); + mysql_free_result(svr_res); + mysql_close(conn); + return strdup("ERROR"); + } + else { + per_res = mysql_store_result(conn); + char* bestserver = strdup(""); + int bestusage = INT_MAX; + while ((svr_row = mysql_fetch_row(svr_res)) != NULL) { + // Am I allowed to use this server? + bool can_use_server = false; + while ((per_row = mysql_fetch_row(per_res)) != NULL) { + if (strcmp(per_row[0], svr_row[0]) == 0) { + can_use_server = true; + } + } + mysql_data_seek(per_res, 0); + if (can_use_server) { + char* safe_servername = get_mysql_escaped_string(conn, svr_row[0]); + asprintf(&query, "SELECT username FROM sessions WHERE servername='%s'", safe_servername); + free(safe_servername); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + free(bestserver); + mysql_free_result(res); + mysql_free_result(svr_res); + mysql_close(conn); + return strdup("ERROR"); + } + else { + free(query); + cnt_res = mysql_store_result(conn); + int usagecount = 0; + while ((cnt_row = mysql_fetch_row(cnt_res)) != NULL) { + usagecount++; + } + mysql_free_result(cnt_res); + if (usagecount < bestusage) { + free(bestserver); + bestserver = strdup(svr_row[0]); + bestusage = usagecount; + } + } + } + } + mysql_free_result(res); + mysql_free_result(svr_res); + mysql_free_result(per_res); + + if (strcmp(bestserver, "") != 0) { + // Insert new information into the sessions database and set status to ALLOCATED + char* safe_servername = get_mysql_escaped_string(conn, bestserver); + char* safe_username = get_mysql_escaped_string(conn, username); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + asprintf(&query, "INSERT INTO sessions (username, arbiter, servername, state) VALUES ('%s', '%s', '%s', '%d')", safe_username, safe_local_machine_fqdn, safe_servername, SM_STATUS_ALLOCATED); + free(safe_local_machine_fqdn); + free(safe_servername); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return strdup("ERROR"); + } + else { + free(query); + + // Insert connection information into the statistics database + char* safe_servername = get_mysql_escaped_string(conn, bestserver); + char* safe_username = get_mysql_escaped_string(conn, username); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid, username) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d', '%s')", timestamp, STATISTICS_NEW_CONNECTION_EVENT, safe_local_machine_fqdn, safe_servername, -1, SM_STATUS_ALLOCATED, safe_username); + free(safe_local_machine_fqdn); + free(safe_servername); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + + mysql_close(conn); + return strdup(bestserver); + } + } + else { + // No usable server found! + mysql_close(conn); + return strdup("ERROR"); + } + } + } + } + else { + char* ret = strdup(row[0]); + mysql_free_result(res); + mysql_close(conn); + return ret; + } + } +} + +char* raptor_sm_get_local_machine_fqdn() { + struct addrinfo hints, *res; + int err; + + char hostname[1024]; + hostname[1023] = '\0'; + gethostname(hostname, 1023); + + memset(&hints, 0, sizeof hints); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0) { + return strdup(""); + } + + char* ret = strdup(res->ai_canonname); + freeaddrinfo(res); + return ret; +} + +char* raptor_sm_get_ip_for_hostname(char* hostname, char* error) { + struct addrinfo hints, *res; + struct in_addr addr; + int err; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET; + + if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0) { + if (error) *error = 1; + return strdup(""); + } + + addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr; + + char* ret = strdup(inet_ntoa(addr)); + freeaddrinfo(res); + if (error) *error = 0; + return ret; +} + +char* raptor_sm_get_hostname_for_username(char* username, bool create) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return strdup("SQLERR100"); + } + + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "SELECT servername FROM sessions WHERE username='%s'", safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return strdup("SQLERR101"); + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + char* ret = strdup(row[0]); + mysql_free_result(res); + mysql_close(conn); + return ret; + } + // Nothing in the DB + mysql_free_result(res); + if (create) { + // Try to allocate a new session on a node + mysql_close(conn); + return raptor_sm_allocate_session(username); + } + else { + mysql_close(conn); + return strdup(""); + } + } +} + +char* raptor_sm_get_hostname_for_display(int display) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return strdup("SQLERR100"); + } + + asprintf(&query, "SELECT servername FROM sessions WHERE display='%d'", display); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return strdup("SQLERR101"); + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + char* ret = strdup(row[0]); + mysql_free_result(res); + mysql_close(conn); + return ret; + } + // Nothing in the DB + mysql_free_result(res); + mysql_close(conn); + return strdup(""); + } +} + +char* raptor_sm_get_ip_for_username(char* username, bool create) { + char* hostname = raptor_sm_get_hostname_for_username(username, create); + char err; + char* ip = raptor_sm_get_ip_for_hostname(hostname, &err); + free(hostname); + if (err) { + raptor_sm_deallocate_session(username); + return strdup("ERROR"); + } + return ip; +} + +bool raptor_sm_sesslimit_reached(char* username) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return true; + } + + // Respect maximum session number for the group for this user + int sesslimit = 0; // Default to denying all sessions + + // Get group for user + char* groupname = get_group_for_user(username); + if (!groupname) { + return true; + } + char* safe_groupname = get_mysql_escaped_string(conn, groupname); + asprintf(&query, "SELECT sesslimit FROM groups WHERE groupname='%s'", safe_groupname); + free(safe_groupname); + if (mysql_query_internal(conn, query)) { + // Server error + free(groupname); + free(query); + mysql_close(conn); + return true; + } + else { + free(query); + res = mysql_store_result(conn); + row = mysql_fetch_row(res); + if (row[0]) { + sesslimit = atoi(row[0]); + } + mysql_free_result(res); + } + + // Figure out how many users are online from this group + int sesscount = 0; + asprintf(&query, "SELECT username FROM sessions WHERE state<>'%d'", SM_STATUS_ALLOCATED); + if (mysql_query_internal(conn, query)) { + // Server error + free(groupname); + free(query); + mysql_close(conn); + return true; + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + char* test_groupname = get_group_for_user(row[0]); + if (!test_groupname) { + free(groupname); + return true; + } + if (strcmp(groupname, test_groupname) == 0) { + sesscount++; + } + free(test_groupname); + } + } + mysql_free_result(res); + + if (sesscount < sesslimit) { + free(groupname); + mysql_close(conn); + return false; + } + free(groupname); + mysql_close(conn); + return true; + } + + // We should never end up here! + free(groupname); + mysql_close(conn); + return true; +} + +pid_t raptor_sm_run_remote_server(char* username, char *const argv[], char* dbfield, int display) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + if (strcmp(dbfield, RAPTOR_SM_SERVER_PID_FIELD) == 0) { + // Respect maximum session number for the group for this user + if (raptor_sm_sesslimit_reached(username)) { + mysql_close(conn); + return -5; + } + } + + // Make sure a server is not already running for this user + // Return the existing PID if it is + char* safe_username = get_mysql_escaped_string(conn, username); + if (strcmp(dbfield, RAPTOR_SM_SERVER_PID_FIELD) == 0) { + asprintf(&query, "SELECT %s,servername FROM sessions WHERE username='%s' AND state<>'%d'", dbfield, safe_username, SM_STATUS_ALLOCATED); + } + else { + asprintf(&query, "SELECT %s,servername FROM sessions WHERE username='%s'", dbfield, safe_username); + } + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + int ret = atoi(row[0]); + if (ret >= 0) { + // Verify existence of PID on remote server + dprint("Verifying process %d on %s...\n\r", ret, row[1]); + char* ip = raptor_sm_get_ip_for_hostname(row[1], 0); + char* command_string; + asprintf(&command_string, "ssh root@%s \'ps -p %d | grep %d\'", ip, ret, ret); + FILE *fp; + char output[1024]; + // Open the command for reading + fp = popen(command_string, "r"); + if (fp == NULL) { + free(ip); + mysql_close(conn); + return -1; + } + // Read the output a line at a time + fgets(output, sizeof(output)-1, fp); + // Close output + pclose(fp); + free(command_string); + free(ip); + dprint("...result was %s\n\r", output); + if (strcmp(output, "") != 0) { + mysql_free_result(res); + mysql_close(conn); + return ret; + } + } + } + } + mysql_free_result(res); + } + + int i; + int n_commands; + + n_commands = 0; + while (argv[n_commands] != NULL) { + n_commands++; + } + + char* ipaddr = raptor_sm_get_ip_for_username(username, true); + + // This is HORRIBLY inefficient + char* command_string = strdup(""); + for (i=0; i<n_commands; i++) { + char* origstr = command_string; + asprintf(&command_string, "%s %s", origstr, argv[i]); + free(origstr); + } + char* origstr = command_string; + +#ifndef RAPTOR_SM_DISABLE_KERBEROS + if (display >= 0) { + uid_t uid = raptor_sm_get_uid_for_user(username); + asprintf(&command_string, "rsync -a /tmp/krb5cc_%d root@%s:/tmp/krb5cc_%d", uid, ipaddr, uid); + dprint("Running command %s...\n\r", command_string); + system(command_string); + free(command_string); + asprintf(&command_string, "rm -f /tmp/krb5cc_%d", uid); + dprint("Running command %s...\n\r", command_string); + system(command_string); + free(command_string); + } +#endif + +#ifndef RAPTOR_SM_DISABLE_PULSEAUDIO + if (display >= 0) { + asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && export PULSE_SERVER=tcp:%s:%d && pulseaudio -D --load=\\\"module-native-protocol-tcp listen=0.0.0.0 auth-ip-acl=%s port=%d\\\"\' &> /dev/null\" &", ipaddr, username, display, ipaddr, (RAPTOR_SM_BASE_PULSEAUDIO_PORT+display), RAPTOR_SM_MANAGEMENT_SERVER_IP_NETRANGE, (RAPTOR_SM_BASE_PULSEAUDIO_PORT+display)); + dprint("Running command %s...\n\r", command_string); + system(command_string); + free(command_string); + } +#endif + + if (strcmp(dbfield, RAPTOR_SM_SERVER_PID_FIELD) == 0) { + asprintf(&command_string, "ssh root@%s \'%s & echo $! &\'", ipaddr, origstr); + } + else { +#if RAPTOR_SM_DISABLE_PULSEAUDIO + asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && %s\' &> /dev/null & echo \\$!\"", ipaddr, username, display, origstr); +#else + //asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && export PULSE_SERVER=tcp:%s:%d && %s\' &> /dev/null & echo \\$!\"", ipaddr, username, display, ipaddr, (RAPTOR_SM_BASE_PULSEAUDIO_PORT+display), origstr); + asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && export PULSE_SERVER=tcp:%s:%d && %s\' &> /var/log/%s_wm_session.log & echo \\$!\"", ipaddr, username, display, ipaddr, (RAPTOR_SM_BASE_PULSEAUDIO_PORT+display), origstr, username); +#endif + } + dprint("Running command %s...\n\r", command_string); + free(origstr); + free(ipaddr); + + FILE *fp; + char output[1024]; + + // Open the command for reading + fp = popen(command_string, "r"); + if (fp == NULL) { + mysql_close(conn); + return -1; + } + + // Read the output a line at a time + fgets(output, sizeof(output)-1, fp); + + // Close output + pclose(fp); + + free(command_string); + + mysql_close(conn); + return atoi(output); +} + +pid_t raptor_sm_get_pid_for_username(char* username, char* dbfield) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Make sure a server is not already running for this user + // Return the existing PID if it is + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "SELECT %s FROM sessions WHERE username='%s'", dbfield, safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + int ret = atoi(row[0]); + if (ret >= 0) { + mysql_free_result(res); + mysql_close(conn); + return ret; + } + } + } + mysql_free_result(res); + } + + mysql_close(conn); + return -3; +} + +int raptor_sm_server_started(char* username, pid_t pid, int display, char* dbfield) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + long long timestamp = time(NULL); + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Update new information into the sessions database and set status to ALLOCATED + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "UPDATE sessions SET %s='%d', stamp_start='%lld', state='%d', display='%d', stamp_statechange='%lld' WHERE username='%s' AND state='%d'", dbfield, pid, timestamp, SM_STATUS_RUNNING, display, timestamp, safe_username, SM_STATUS_ALLOCATED); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + + // Insert connection information into the statistics database + char* current_server = raptor_sm_get_hostname_for_display(display); + char* safe_servername = get_mysql_escaped_string(conn, current_server); + char* safe_username = get_mysql_escaped_string(conn, username); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid, username) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d', '%s')", timestamp, STATISTICS_CONNECTION_STATUS_EVENT, safe_local_machine_fqdn, safe_servername, display, SM_STATUS_RUNNING, safe_username); + free(safe_servername); + free(safe_username); + free(safe_local_machine_fqdn); + free(current_server); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + + mysql_close(conn); + return 0; + } +} + +int raptor_sm_wm_started(char* username, pid_t pid, char* dbfield) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Update new information into the sessions database and set status to ALLOCATED + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "UPDATE sessions SET %s='%d' WHERE username='%s'", dbfield, pid, safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + mysql_close(conn); + return 0; + } +} + +int raptor_sm_get_display_for_username(char* username) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "SELECT display FROM sessions WHERE username='%s'", safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + int ret = atoi(row[0]); + mysql_free_result(res); + mysql_close(conn); + return ret; + } + else { + mysql_free_result(res); + mysql_close(conn); + return -3; + } + } + // Nothing in the DB + mysql_free_result(res); + mysql_close(conn); + return -4; + } +} + +char* raptor_sm_get_username_for_display_and_hostname(int display, char* hostname) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return strdup(""); + } + + char* safe_hostname = get_mysql_escaped_string(conn, hostname); + asprintf(&query, "SELECT username FROM sessions WHERE display='%d' AND servername='%s'", display, safe_hostname); + free(safe_hostname); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return strdup(""); + } + else { + free(query); + res = mysql_store_result(conn); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + char* ret = strdup(row[0]); + mysql_free_result(res); + mysql_close(conn); + return ret; + } + else { + mysql_free_result(res); + mysql_close(conn); + return strdup(""); + } + } + // Nothing in the DB + mysql_free_result(res); + mysql_close(conn); + return strdup(""); + } +} + +void raptor_sm_wait_for_pid_exit(char* username, pid_t pid) { + char* ipaddr = raptor_sm_get_ip_for_username(username, false); + + char* command_string; + asprintf(&command_string, "ssh root@%s \'while [[ `ps -p %d | grep %d` != \"\" ]]; do sleep 1; done\'", ipaddr, pid, pid); + system(command_string); + free(command_string); +} + +void raptor_sm_session_terminated(char* username) { + raptor_sm_deallocate_session(username); +} + +int raptor_sm_wm_terminated(char* username) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + long long timestamp = time(NULL); + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Update new information into the sessions database + char* safe_username = get_mysql_escaped_string(conn, username); + asprintf(&query, "UPDATE sessions SET %s=NULL WHERE username='%s'", RAPTOR_SM_WM_PID_FIELD, safe_username); + free(safe_username); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + mysql_close(conn); + return 0; + } +} + +int raptor_sm_get_new_unique_display(int mindisplay, int maxdisplay) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + asprintf(&query, "SELECT display FROM sessions"); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + dprint("[ERROR] MySQL connection FAILED [%s]\n\r", mysql_error(conn)); + mysql_close(conn); + return -2; + } + else { + res = mysql_store_result(conn); + int freedisp; + bool dispinuse; + for (freedisp=mindisplay; freedisp<maxdisplay; freedisp++) { + dispinuse = false; + mysql_data_seek(res, 0); + while ((row = mysql_fetch_row(res)) != NULL) { + if (row[0]) { + if (atoi(row[0]) == freedisp) { + dispinuse = true; + } + } + } + if (dispinuse == false) { + break; + } + } + mysql_free_result(res); + mysql_close(conn); + return freedisp; + } +} + +char raptor_sm_set_session_state(int display, int state) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + long long timestamp = time(NULL); + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Update new state into the sessions database + asprintf(&query, "UPDATE sessions SET state='%d', stamp_statechange='%lld' WHERE display='%d'", state, timestamp, display); + if (mysql_query_internal(conn, query)) { + // Server error + free(query); + mysql_close(conn); + return -2; + } + else { + free(query); + + // Insert connection information into the statistics database + char* hostname = raptor_sm_get_hostname_for_display(display); + char* username = raptor_sm_get_username_for_display_and_hostname(display, hostname); + char* safe_servername = get_mysql_escaped_string(conn, hostname); + char* safe_username = get_mysql_escaped_string(conn, username); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid, username) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d', '%s')", timestamp, STATISTICS_CONNECTION_STATUS_EVENT, safe_local_machine_fqdn, safe_servername, display, state, safe_username); + free(safe_servername); + free(safe_username); + free(safe_local_machine_fqdn); + free(hostname); + free(username); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + + mysql_close(conn); + return 0; + } +} + +void raptor_sm_run_remote_desktop(char* username, int display, char* executable) { + char* ipaddr = raptor_sm_get_ip_for_username(username, true); + char* command_string; +#if RAPTOR_SM_DISABLE_PULSEAUDIO + asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && %s && exit\' &> /dev/null\"", ipaddr, username, display, executable); +#else + asprintf(&command_string, "ssh root@%s \"su %s -c \'export DISPLAY=:%d && export PULSE_SERVER=tcp:%s:%d && %s && exit\' &> /dev/null\"", ipaddr, username, display, ipaddr, (RAPTOR_SM_BASE_PULSEAUDIO_PORT+display), executable); +#endif + system(command_string); + free(command_string); +} + +void raptor_sm_terminate_server(char* username) { + char* ipaddr = raptor_sm_get_ip_for_username(username, true); + char* command_string; + + // Terminate remote X server + pid_t pid = raptor_sm_get_pid_for_username(username, RAPTOR_SM_SERVER_PID_FIELD); + if (pid > 0) { + asprintf(&command_string, "ssh root@%s \'kill -9 %ld\'", ipaddr, pid); + system(command_string); + free(command_string); + } +} + +int raptor_sm_stats_report_server_start(char* hostname) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Insert information into the statistics database + char* safe_servername = get_mysql_escaped_string(conn, hostname); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d')", timestamp, STATISTICS_SERVER_START_EVENT, safe_local_machine_fqdn, safe_servername, -1, -1); + free(safe_servername); + free(safe_local_machine_fqdn); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + mysql_close(conn); + + return 0; +} + +int raptor_sm_stats_report_server_stop(char* hostname) { + MYSQL_RES *res; + MYSQL_ROW row; + char* query; + + MYSQL *conn = connect_if_needed(); + if (!conn) { + return -1; + } + + // Insert information into the statistics database + char* safe_servername = get_mysql_escaped_string(conn, hostname); + char* safe_local_machine_fqdn = get_mysql_escaped_string(conn, local_machine_fqdn); + long long timestamp = time(NULL); + asprintf(&query, "INSERT INTO statistics (timestamp, eventtypeid, arbiter, servername, display, typeid) VALUES ('%lld', '%d', '%s', '%s', '%d', '%d')", timestamp, STATISTICS_SERVER_STOP_EVENT, safe_local_machine_fqdn, safe_servername, -1, -1); + free(safe_servername); + free(safe_local_machine_fqdn); + if (mysql_query_internal(conn, query)) { + // Server error + dprint("Unable to insert data into statistics database! [%s]\n\r", mysql_error(conn)); + } + free(query); + mysql_close(conn); + + return 0; +} |
