diff --git a/src/config.c b/src/config.c index fd892979..12631088 100644 --- a/src/config.c +++ b/src/config.c @@ -45,6 +45,8 @@ const struct vpn_config invalid_cfg = { .password = {'\0'}, .password_set = 0, .cookie = NULL, + .saml_port = 0, + .saml_session_id = {'\0'}, .otp = {'\0'}, .otp_prompt = NULL, .otp_delay = -1, @@ -418,9 +420,7 @@ int load_config(struct vpn_config *cfg, const char *filename) if (strncmp(cfg->user_cert, "pkcs11:", 7) == 0) cfg->use_engine = 1; } else if (strcmp(key, "saml-login") == 0) { - free(cfg->saml_port); - cfg->saml_port = atol(val); - continue; + cfg->saml_port = atoi(val); } else if (strcmp(key, "user-key") == 0) { free(cfg->user_key); cfg->user_key = strdup(val); diff --git a/src/config.h b/src/config.h index 2ddd2c6b..352caae2 100644 --- a/src/config.h +++ b/src/config.h @@ -81,6 +81,7 @@ struct x509_digest { * We believe we are on the safe side using this value. */ #define MAX_DOMAIN_LENGTH 256 +#define MAX_SAML_SESSION_ID_LENGTH 1024 struct vpn_config { char gateway_host[GATEWAY_HOST_SIZE + 1]; @@ -91,8 +92,8 @@ struct vpn_config { int password_set; char otp[OTP_SIZE + 1]; char *cookie; - int saml_port; - char saml_session_id[1024]; + int saml_port; + char saml_session_id[MAX_SAML_SESSION_ID_LENGTH]; char *otp_prompt; unsigned int otp_delay; int no_ftm_push; diff --git a/src/http.c b/src/http.c index 8d6d595c..d8a579d5 100644 --- a/src/http.c +++ b/src/http.c @@ -622,7 +622,7 @@ static int try_otp_auth(struct tunnel *tunnel, const char *buffer, /* - * Authenticates to gateway by sending username and password. + * Authenticates to gateway by sending a SAML session token. * * @return 1 in case of success * < 0 in case of error @@ -634,12 +634,15 @@ int saml_login(struct tunnel *tunnel) int ret; ssl_connect(tunnel); - char uri[1024]; - snprintf(uri, sizeof(uri), "/remote/saml/auth_id?id=%s", tunnel->config->saml_session_id); + char uri_pattern[] = "/remote/saml/auth_id?id=%s"; + int required_size = snprintf(NULL, 0, uri_pattern, tunnel->config->saml_session_id) + 1; + char *uri = alloca(required_size); + snprintf(uri, required_size, uri_pattern, tunnel->config->saml_session_id); + char *response; uint32_t response_size = 0; ret = http_request(tunnel, "GET", uri, "", &response, &response_size); - if(ret != 1 || response_size <= 15) return ret; + if(ret != 1 || response_size <= 15) return -1; if (memcmp(response, "HTTP/1.1 200 OK", 15) != 0){ log_error("SAML login failed: %s\n", response); return ret; @@ -648,11 +651,9 @@ int saml_login(struct tunnel *tunnel) if (ret == ERR_HTTP_NO_COOKIE){ log_error("SAML login failed: no cookie\n"); return ret; - } - - // free(response); - + } + free(response); return ret; } diff --git a/src/http.h b/src/http.h index 08cd6899..96cd066c 100644 --- a/src/http.h +++ b/src/http.h @@ -19,7 +19,6 @@ #define OPENFORTIVPN_HTTP_H #include "tunnel.h" -#include "config.h" #include diff --git a/src/http_server.c b/src/http_server.c index ca94af74..b9efeed2 100644 --- a/src/http_server.c +++ b/src/http_server.c @@ -1,54 +1,42 @@ -#include #include #include #include -#include "config.h" -#include "log.h" -#include -#include "tunnel.h" #include -#include #include - +#include "config.h" +#include "log.h" +#include "tunnel.h" int process_request(int new_socket, char *id) { - log_info("Processing request\n"); + log_info("Processing HTTP SAML request\n"); int flag = 1; setsockopt(new_socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); - const int buffer_size = 2048; - char *response[buffer_size]; - memset(response,' ',buffer_size); - response[buffer_size - 1] = '\0'; - char *reply = "HTTP/1.1 200 OK\r\n" + const char *reply = "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "SAML Login...\r\n\0"; - memcpy(response,reply,strlen(reply)); - // Read the request - ssize_t write_result = write(new_socket, response, buffer_size); + ssize_t write_result = write(new_socket, reply, strlen(reply)); (void)write_result; - // dup2(new_socket, STDOUT_FILENO); - // dup2(new_socket, STDERR_FILENO); - - - + // Read the request char request[1024]; ssize_t read_result = read(new_socket, request, sizeof(request)); // Check for '=id' in the response - if (read_result < 0 || strlen(request) < 10 || strncmp(request, "GET /?id=", 9) != 0) { + // If the recevied request from the server is larger than the buffer, the result will not be null-terminated. + // Causing strlen to behave wrong. + if (read_result < 0 || read_result == sizeof(request) || strlen(request) < 10 || strncmp(request, "GET /?id=", 9) != 0) { log_error("Bad request\n"); return -1; } // Extract the id const int id_start = 9; - char *id_end = memchr(&request[id_start], ' ', 1000); + char *id_end = memchr(&request[id_start], ' ', sizeof(request) - id_start); if (id_end == NULL) { log_error("Bad request format\n"); @@ -57,7 +45,7 @@ int process_request(int new_socket, char *id) { int id_length = id_end - &request[id_start]; - if(id_length == 0 || id_length > 1000) { + if(id_length == 0 || id_length > MAX_SAML_SESSION_ID_LENGTH) { log_error("Bad request id\n"); return -1; } @@ -69,7 +57,7 @@ int process_request(int new_socket, char *id) { log_error("Invalid id format\n"); return -1; } - // close(new_socket); + close(new_socket); log_info("Extracted id: %s\n", id); return 0; } @@ -94,6 +82,7 @@ void* start_http_server(void *void_config) { // Forcefully attaching socket to the port if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + close(server_fd); log_error("Failed to set socket options\n"); return NULL; } @@ -104,52 +93,34 @@ void* start_http_server(void *void_config) { // Forcefully attaching socket to the port if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + close(server_fd); log_error("Failed to bind socket to port %d \n",saml_port); return NULL; } if (listen(server_fd, 3) < 0) { + close(server_fd); log_error("Failed to listen on socket\n"); return NULL; } log_info("Listening for saml login on port: %d\n", saml_port); - int running = 1; - - pthread_t vpn_thread = 0; - - while(running) { + while(1) { if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { log_error("Failed to accept connection\n"); continue; } int result = process_request(new_socket, config->saml_session_id); + close(new_socket); if(result != 0) { log_error("Failed to process request\n"); continue; } - - - // Kill previous thread if it exists - if (vpn_thread != 0) { - log_error("Stop existing tunnel\n"); - pthread_kill(vpn_thread,SIGTERM); - pthread_join(vpn_thread, NULL); - } - - int thread_create_result = pthread_create(&vpn_thread, NULL, run_tunnel_wrapper, (void *)config); - if (thread_create_result != 0) { - log_error("Failed to create VPN thread\n"); - continue; - } - - - // pthread_detach(vpn_thread); - - result = 0; + break; } + close(server_fd); return NULL; } diff --git a/src/main.c b/src/main.c index e2add2a8..de499dcf 100644 --- a/src/main.c +++ b/src/main.c @@ -228,7 +228,7 @@ int main(int argc, char *argv[]) .password_set = 0, .cookie = NULL, .saml_port = 0, - .saml_session_id = NULL, + .saml_session_id = {'\0'}, .otp = {'\0'}, .otp_prompt = NULL, .otp_delay = 0, @@ -290,7 +290,7 @@ int main(int argc, char *argv[]) {"password", required_argument, NULL, 'p'}, {"cookie", required_argument, NULL, 0}, {"cookie-on-stdin", no_argument, NULL, 0}, - {"saml-login", optional_argument, NULL, 0}, + {"saml-login", optional_argument, NULL, 0}, {"otp", required_argument, NULL, 'o'}, {"otp-prompt", required_argument, NULL, 0}, {"otp-delay", required_argument, NULL, 0}, @@ -615,7 +615,7 @@ int main(int argc, char *argv[]) if(optarg != NULL){ port = strtol(optarg, NULL, 0); } - if (port < 0 || port > UINT_MAX) { + if (port < 0 || port > 65535) { log_warn("Invalid saml listen port: %s! Default port is 8020 \n", optarg); break; } @@ -732,7 +732,7 @@ int main(int argc, char *argv[]) goto user_error; } // If username but no password given, interactively ask user - if (!cfg.password_set && cfg.username[0] != '\0' && !cfg.cookie) { + if (!cfg.password_set && cfg.username[0] != '\0' && !cfg.cookie && !cfg.saml_port) { char hint[USERNAME_SIZE + 1 + REALM_SIZE + 1 + GATEWAY_HOST_SIZE + 10]; sprintf(hint, "%s_%s_%s_password", @@ -761,12 +761,16 @@ int main(int argc, char *argv[]) if(pthread_create(&server_thread, NULL, start_http_server, &cfg) != 0){ log_error("Failed to create saml login server thread\n"); - // ret = EXIT_FAILURE; + ret = EXIT_FAILURE; + goto exit; + } + log_debug("Running http server on port %d\n", cfg.saml_port); + pthread_join(server_thread, NULL); + + if (strlen(cfg.saml_session_id) == 0) { + log_error("Failed to receive SAML session id\n"); goto exit; } - // log_debug("Running http server on port %d\n", cfg.saml_port); - while(get_sig_received() == 0); - goto exit; } do {